Program.cs 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133
  1. using OpenTK.Graphics.OpenGL;
  2. using Ryujinx.Common.Logging;
  3. using Ryujinx.Graphics.GAL;
  4. using Ryujinx.Graphics.Shader.CodeGen.Glsl;
  5. using System;
  6. using System.Buffers.Binary;
  7. using System.Collections.Generic;
  8. using System.Linq;
  9. namespace Ryujinx.Graphics.OpenGL
  10. {
  11. class Program : IProgram
  12. {
  13. public int Handle { get; private set; }
  14. public bool IsLinked
  15. {
  16. get
  17. {
  18. if (_status == ProgramLinkStatus.Incomplete)
  19. {
  20. CheckProgramLink(true);
  21. }
  22. return _status == ProgramLinkStatus.Success;
  23. }
  24. }
  25. private ProgramLinkStatus _status = ProgramLinkStatus.Incomplete;
  26. private IShader[] _shaders;
  27. public Program(IShader[] shaders)
  28. {
  29. Handle = GL.CreateProgram();
  30. GL.ProgramParameter(Handle, ProgramParameterName.ProgramBinaryRetrievableHint, 1);
  31. for (int index = 0; index < shaders.Length; index++)
  32. {
  33. int shaderHandle = ((Shader)shaders[index]).Handle;
  34. GL.AttachShader(Handle, shaderHandle);
  35. }
  36. GL.LinkProgram(Handle);
  37. _shaders = shaders;
  38. }
  39. public Program(ReadOnlySpan<byte> code)
  40. {
  41. BinaryFormat binaryFormat = (BinaryFormat)BinaryPrimitives.ReadInt32LittleEndian(code.Slice(code.Length - 4, 4));
  42. Handle = GL.CreateProgram();
  43. unsafe
  44. {
  45. fixed (byte* ptr = code)
  46. {
  47. GL.ProgramBinary(Handle, binaryFormat, (IntPtr)ptr, code.Length - 4);
  48. }
  49. }
  50. }
  51. public void Bind()
  52. {
  53. GL.UseProgram(Handle);
  54. }
  55. public ProgramLinkStatus CheckProgramLink(bool blocking)
  56. {
  57. if (!blocking && HwCapabilities.SupportsParallelShaderCompile)
  58. {
  59. GL.GetProgram(Handle, (GetProgramParameterName)ArbParallelShaderCompile.CompletionStatusArb, out int completed);
  60. if (completed == 0)
  61. {
  62. return ProgramLinkStatus.Incomplete;
  63. }
  64. }
  65. GL.GetProgram(Handle, GetProgramParameterName.LinkStatus, out int status);
  66. if (_shaders != null)
  67. {
  68. for (int index = 0; index < _shaders.Length; index++)
  69. {
  70. int shaderHandle = ((Shader)_shaders[index]).Handle;
  71. GL.DetachShader(Handle, shaderHandle);
  72. }
  73. _shaders = null;
  74. }
  75. if (status == 0)
  76. {
  77. // Use GL.GetProgramInfoLog(Handle), it may be too long to print on the log.
  78. _status = ProgramLinkStatus.Failure;
  79. Logger.Debug?.Print(LogClass.Gpu, "Shader linking failed.");
  80. }
  81. else
  82. {
  83. _status = ProgramLinkStatus.Success;
  84. }
  85. return _status;
  86. }
  87. public byte[] GetBinary()
  88. {
  89. GL.GetProgram(Handle, (GetProgramParameterName)All.ProgramBinaryLength, out int size);
  90. byte[] data = new byte[size + 4];
  91. GL.GetProgramBinary(Handle, size, out _, out BinaryFormat binFormat, data);
  92. BinaryPrimitives.WriteInt32LittleEndian(data.AsSpan().Slice(size, 4), (int)binFormat);
  93. return data;
  94. }
  95. public void Dispose()
  96. {
  97. if (Handle != 0)
  98. {
  99. GL.DeleteProgram(Handle);
  100. Handle = 0;
  101. }
  102. }
  103. }
  104. }