Ryujinx/Ryujinx.Graphics.OpenGL/Program.cs
gdkchan 7e967d796c
Stop using glTransformFeedbackVaryings and use explicit layout on the shader (#3012)
* Stop using glTransformFeedbackVarying and use explicit layout on the shader

* This is no longer needed

* Shader cache version bump

* Fix gl_PerVertex output for tessellation control shaders
2022-01-21 12:35:21 -03:00

133 lines
3.6 KiB
C#

using OpenTK.Graphics.OpenGL;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Shader.CodeGen.Glsl;
using System;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Linq;
namespace Ryujinx.Graphics.OpenGL
{
class Program : IProgram
{
public int Handle { get; private set; }
public bool IsLinked
{
get
{
if (_status == ProgramLinkStatus.Incomplete)
{
CheckProgramLink(true);
}
return _status == ProgramLinkStatus.Success;
}
}
private ProgramLinkStatus _status = ProgramLinkStatus.Incomplete;
private IShader[] _shaders;
public Program(IShader[] shaders)
{
Handle = GL.CreateProgram();
GL.ProgramParameter(Handle, ProgramParameterName.ProgramBinaryRetrievableHint, 1);
for (int index = 0; index < shaders.Length; index++)
{
int shaderHandle = ((Shader)shaders[index]).Handle;
GL.AttachShader(Handle, shaderHandle);
}
GL.LinkProgram(Handle);
_shaders = shaders;
}
public Program(ReadOnlySpan<byte> code)
{
BinaryFormat binaryFormat = (BinaryFormat)BinaryPrimitives.ReadInt32LittleEndian(code.Slice(code.Length - 4, 4));
Handle = GL.CreateProgram();
unsafe
{
fixed (byte* ptr = code)
{
GL.ProgramBinary(Handle, binaryFormat, (IntPtr)ptr, code.Length - 4);
}
}
}
public void Bind()
{
GL.UseProgram(Handle);
}
public ProgramLinkStatus CheckProgramLink(bool blocking)
{
if (!blocking && HwCapabilities.SupportsParallelShaderCompile)
{
GL.GetProgram(Handle, (GetProgramParameterName)ArbParallelShaderCompile.CompletionStatusArb, out int completed);
if (completed == 0)
{
return ProgramLinkStatus.Incomplete;
}
}
GL.GetProgram(Handle, GetProgramParameterName.LinkStatus, out int status);
if (_shaders != null)
{
for (int index = 0; index < _shaders.Length; index++)
{
int shaderHandle = ((Shader)_shaders[index]).Handle;
GL.DetachShader(Handle, shaderHandle);
}
_shaders = null;
}
if (status == 0)
{
// Use GL.GetProgramInfoLog(Handle), it may be too long to print on the log.
_status = ProgramLinkStatus.Failure;
Logger.Debug?.Print(LogClass.Gpu, "Shader linking failed.");
}
else
{
_status = ProgramLinkStatus.Success;
}
return _status;
}
public byte[] GetBinary()
{
GL.GetProgram(Handle, (GetProgramParameterName)All.ProgramBinaryLength, out int size);
byte[] data = new byte[size + 4];
GL.GetProgramBinary(Handle, size, out _, out BinaryFormat binFormat, data);
BinaryPrimitives.WriteInt32LittleEndian(data.AsSpan().Slice(size, 4), (int)binFormat);
return data;
}
public void Dispose()
{
if (Handle != 0)
{
GL.DeleteProgram(Handle);
Handle = 0;
}
}
}
}