Program.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. using OpenTK.Graphics.OpenGL;
  2. using Ryujinx.Common.Logging;
  3. using Ryujinx.Graphics.GAL;
  4. using Ryujinx.Graphics.Shader;
  5. using Ryujinx.Graphics.Shader.Translation;
  6. using System;
  7. using System.Buffers.Binary;
  8. namespace Ryujinx.Graphics.OpenGL
  9. {
  10. class Program : IProgram
  11. {
  12. public int Handle { get; private set; }
  13. public bool IsLinked
  14. {
  15. get
  16. {
  17. if (_status == ProgramLinkStatus.Incomplete)
  18. {
  19. CheckProgramLink(true);
  20. }
  21. return _status == ProgramLinkStatus.Success;
  22. }
  23. }
  24. private ProgramLinkStatus _status = ProgramLinkStatus.Incomplete;
  25. private int[] _shaderHandles;
  26. public bool HasFragmentShader;
  27. public int FragmentOutputMap { get; }
  28. public Program(ShaderSource[] shaders, int fragmentOutputMap)
  29. {
  30. Handle = GL.CreateProgram();
  31. GL.ProgramParameter(Handle, ProgramParameterName.ProgramBinaryRetrievableHint, 1);
  32. _shaderHandles = new int[shaders.Length];
  33. for (int index = 0; index < shaders.Length; index++)
  34. {
  35. ShaderSource shader = shaders[index];
  36. if (shader.Stage == ShaderStage.Fragment)
  37. {
  38. HasFragmentShader = true;
  39. }
  40. int shaderHandle = GL.CreateShader(shader.Stage.Convert());
  41. switch (shader.Language)
  42. {
  43. case TargetLanguage.Glsl:
  44. GL.ShaderSource(shaderHandle, shader.Code);
  45. GL.CompileShader(shaderHandle);
  46. break;
  47. case TargetLanguage.Spirv:
  48. GL.ShaderBinary(1, ref shaderHandle, (BinaryFormat)All.ShaderBinaryFormatSpirVArb, shader.BinaryCode, shader.BinaryCode.Length);
  49. GL.SpecializeShader(shaderHandle, "main", 0, (int[])null, (int[])null);
  50. break;
  51. }
  52. GL.AttachShader(Handle, shaderHandle);
  53. _shaderHandles[index] = shaderHandle;
  54. }
  55. GL.LinkProgram(Handle);
  56. FragmentOutputMap = fragmentOutputMap;
  57. }
  58. public Program(ReadOnlySpan<byte> code, bool hasFragmentShader, int fragmentOutputMap)
  59. {
  60. Handle = GL.CreateProgram();
  61. if (code.Length >= 4)
  62. {
  63. BinaryFormat binaryFormat = (BinaryFormat)BinaryPrimitives.ReadInt32LittleEndian(code.Slice(code.Length - 4, 4));
  64. unsafe
  65. {
  66. fixed (byte* ptr = code)
  67. {
  68. GL.ProgramBinary(Handle, binaryFormat, (IntPtr)ptr, code.Length - 4);
  69. }
  70. }
  71. }
  72. HasFragmentShader = hasFragmentShader;
  73. FragmentOutputMap = fragmentOutputMap;
  74. }
  75. public void Bind()
  76. {
  77. GL.UseProgram(Handle);
  78. }
  79. public ProgramLinkStatus CheckProgramLink(bool blocking)
  80. {
  81. if (!blocking && HwCapabilities.SupportsParallelShaderCompile)
  82. {
  83. GL.GetProgram(Handle, (GetProgramParameterName)ArbParallelShaderCompile.CompletionStatusArb, out int completed);
  84. if (completed == 0)
  85. {
  86. return ProgramLinkStatus.Incomplete;
  87. }
  88. }
  89. GL.GetProgram(Handle, GetProgramParameterName.LinkStatus, out int status);
  90. DeleteShaders();
  91. if (status == 0)
  92. {
  93. // Use GL.GetProgramInfoLog(Handle), it may be too long to print on the log.
  94. _status = ProgramLinkStatus.Failure;
  95. Logger.Debug?.Print(LogClass.Gpu, "Shader linking failed.");
  96. }
  97. else
  98. {
  99. _status = ProgramLinkStatus.Success;
  100. }
  101. return _status;
  102. }
  103. public byte[] GetBinary()
  104. {
  105. GL.GetProgram(Handle, (GetProgramParameterName)All.ProgramBinaryLength, out int size);
  106. byte[] data = new byte[size + 4];
  107. GL.GetProgramBinary(Handle, size, out _, out BinaryFormat binFormat, data);
  108. BinaryPrimitives.WriteInt32LittleEndian(data.AsSpan(size, 4), (int)binFormat);
  109. return data;
  110. }
  111. private void DeleteShaders()
  112. {
  113. if (_shaderHandles != null)
  114. {
  115. foreach (int shaderHandle in _shaderHandles)
  116. {
  117. GL.DetachShader(Handle, shaderHandle);
  118. GL.DeleteShader(shaderHandle);
  119. }
  120. _shaderHandles = null;
  121. }
  122. }
  123. public void Dispose()
  124. {
  125. if (Handle != 0)
  126. {
  127. DeleteShaders();
  128. GL.DeleteProgram(Handle);
  129. Handle = 0;
  130. }
  131. }
  132. }
  133. }