Ryujinx/Ryujinx.Graphics.OpenGL/VertexArray.cs
gdkchan 9948a7be53
Support constant attributes (with a value of zero) (#1066)
* Support constant attributes (with a value of zero)

* Remove extra line
2020-03-30 13:11:24 +11:00

149 lines
4.3 KiB
C#

using OpenTK.Graphics.OpenGL;
using Ryujinx.Graphics.GAL;
using System;
namespace Ryujinx.Graphics.OpenGL
{
class VertexArray : IDisposable
{
public int Handle { get; private set; }
private bool _needsAttribsUpdate;
private VertexBufferDescriptor[] _vertexBuffers;
private VertexAttribDescriptor[] _vertexAttribs;
public VertexArray()
{
Handle = GL.GenVertexArray();
}
public void Bind()
{
GL.BindVertexArray(Handle);
}
public void SetVertexBuffers(VertexBufferDescriptor[] vertexBuffers)
{
int bindingIndex = 0;
foreach (VertexBufferDescriptor vb in vertexBuffers)
{
if (vb.Buffer.Buffer != null)
{
int bufferHandle = ((Buffer)vb.Buffer.Buffer).Handle;
GL.BindVertexBuffer(bindingIndex, bufferHandle, (IntPtr)vb.Buffer.Offset, vb.Stride);
GL.VertexBindingDivisor(bindingIndex, vb.Divisor);
}
else
{
GL.BindVertexBuffer(bindingIndex, 0, IntPtr.Zero, 0);
}
bindingIndex++;
}
_vertexBuffers = vertexBuffers;
_needsAttribsUpdate = true;
}
public void SetVertexAttributes(VertexAttribDescriptor[] vertexAttribs)
{
int attribIndex = 0;
foreach (VertexAttribDescriptor attrib in vertexAttribs)
{
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).
GL.DisableVertexAttribArray(attribIndex);
}
else
{
GL.EnableVertexAttribArray(attribIndex);
}
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(attribIndex, size, type, fmtInfo.Normalized, offset);
}
else
{
VertexAttribIntegerType type = (VertexAttribIntegerType)fmtInfo.PixelType;
GL.VertexAttribIFormat(attribIndex, size, type, offset);
}
GL.VertexAttribBinding(attribIndex, attrib.BufferIndex);
attribIndex++;
}
for (; attribIndex < 16; attribIndex++)
{
GL.DisableVertexAttribArray(attribIndex);
}
_vertexAttribs = vertexAttribs;
}
public void SetIndexBuffer(Buffer indexBuffer)
{
GL.BindBuffer(BufferTarget.ElementArrayBuffer, indexBuffer?.Handle ?? 0);
}
public void Validate()
{
for (int attribIndex = 0; attribIndex < _vertexAttribs.Length; attribIndex++)
{
VertexAttribDescriptor attrib = _vertexAttribs[attribIndex];
if ((uint)attrib.BufferIndex >= _vertexBuffers.Length)
{
GL.DisableVertexAttribArray(attribIndex);
continue;
}
if (_vertexBuffers[attrib.BufferIndex].Buffer.Buffer == null)
{
GL.DisableVertexAttribArray(attribIndex);
continue;
}
if (_needsAttribsUpdate && !attrib.IsZero)
{
GL.EnableVertexAttribArray(attribIndex);
}
}
_needsAttribsUpdate = false;
}
public void Dispose()
{
if (Handle != 0)
{
GL.DeleteVertexArray(Handle);
Handle = 0;
}
}
}
}