TextureCopyMS.cs 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276
  1. using OpenTK.Graphics.OpenGL;
  2. using Ryujinx.Graphics.GAL;
  3. using System;
  4. using System.Numerics;
  5. namespace Ryujinx.Graphics.OpenGL.Image
  6. {
  7. class TextureCopyMS
  8. {
  9. private const string ComputeShaderMSToNonMS = @"#version 450 core
  10. layout (binding = 0, $FORMAT$) uniform uimage2DMS imgIn;
  11. layout (binding = 1, $FORMAT$) uniform uimage2D imgOut;
  12. layout (local_size_x = 32, local_size_y = 32, local_size_z = 1) in;
  13. void main()
  14. {
  15. uvec2 coords = gl_GlobalInvocationID.xy;
  16. ivec2 imageSz = imageSize(imgOut);
  17. if (int(coords.x) >= imageSz.x || int(coords.y) >= imageSz.y)
  18. {
  19. return;
  20. }
  21. int inSamples = imageSamples(imgIn);
  22. int samplesInXLog2 = 0;
  23. int samplesInYLog2 = 0;
  24. switch (inSamples)
  25. {
  26. case 2:
  27. samplesInXLog2 = 1;
  28. break;
  29. case 4:
  30. samplesInXLog2 = 1;
  31. samplesInYLog2 = 1;
  32. break;
  33. case 8:
  34. samplesInXLog2 = 2;
  35. samplesInYLog2 = 1;
  36. break;
  37. case 16:
  38. samplesInXLog2 = 2;
  39. samplesInYLog2 = 2;
  40. break;
  41. }
  42. int samplesInX = 1 << samplesInXLog2;
  43. int samplesInY = 1 << samplesInYLog2;
  44. int sampleIdx = (int(coords.x) & (samplesInX - 1)) | ((int(coords.y) & (samplesInY - 1)) << samplesInXLog2);
  45. uvec4 value = imageLoad(imgIn, ivec2(int(coords.x) >> samplesInXLog2, int(coords.y) >> samplesInYLog2), sampleIdx);
  46. imageStore(imgOut, ivec2(coords), value);
  47. }";
  48. private const string ComputeShaderNonMSToMS = @"#version 450 core
  49. layout (binding = 0, $FORMAT$) uniform uimage2D imgIn;
  50. layout (binding = 1, $FORMAT$) uniform uimage2DMS imgOut;
  51. layout (local_size_x = 32, local_size_y = 32, local_size_z = 1) in;
  52. void main()
  53. {
  54. uvec2 coords = gl_GlobalInvocationID.xy;
  55. ivec2 imageSz = imageSize(imgIn);
  56. if (int(coords.x) >= imageSz.x || int(coords.y) >= imageSz.y)
  57. {
  58. return;
  59. }
  60. int outSamples = imageSamples(imgOut);
  61. int samplesInXLog2 = 0;
  62. int samplesInYLog2 = 0;
  63. switch (outSamples)
  64. {
  65. case 2:
  66. samplesInXLog2 = 1;
  67. break;
  68. case 4:
  69. samplesInXLog2 = 1;
  70. samplesInYLog2 = 1;
  71. break;
  72. case 8:
  73. samplesInXLog2 = 2;
  74. samplesInYLog2 = 1;
  75. break;
  76. case 16:
  77. samplesInXLog2 = 2;
  78. samplesInYLog2 = 2;
  79. break;
  80. }
  81. int samplesInX = 1 << samplesInXLog2;
  82. int samplesInY = 1 << samplesInYLog2;
  83. int sampleIdx = (int(coords.x) & (samplesInX - 1)) | ((int(coords.y) & (samplesInY - 1)) << samplesInXLog2);
  84. uvec4 value = imageLoad(imgIn, ivec2(coords));
  85. imageStore(imgOut, ivec2(int(coords.x) >> samplesInXLog2, int(coords.y) >> samplesInYLog2), sampleIdx, value);
  86. }";
  87. private readonly OpenGLRenderer _renderer;
  88. private int[] _msToNonMSProgramHandles;
  89. private int[] _nonMSToMSProgramHandles;
  90. public TextureCopyMS(OpenGLRenderer renderer)
  91. {
  92. _renderer = renderer;
  93. _msToNonMSProgramHandles = new int[5];
  94. _nonMSToMSProgramHandles = new int[5];
  95. }
  96. public void CopyMSToNonMS(ITextureInfo src, ITextureInfo dst, int srcLayer, int dstLayer, int depth)
  97. {
  98. TextureCreateInfo srcInfo = src.Info;
  99. TextureCreateInfo dstInfo = dst.Info;
  100. int srcHandle = CreateViewIfNeeded(src);
  101. int dstHandle = CreateViewIfNeeded(dst);
  102. int dstWidth = dstInfo.Width;
  103. int dstHeight = dstInfo.Height;
  104. GL.UseProgram(GetMSToNonMSShader(srcInfo.BytesPerPixel));
  105. for (int z = 0; z < depth; z++)
  106. {
  107. GL.BindImageTexture(0, srcHandle, 0, false, srcLayer + z, TextureAccess.ReadOnly, GetFormat(srcInfo.BytesPerPixel));
  108. GL.BindImageTexture(1, dstHandle, 0, false, dstLayer + z, TextureAccess.WriteOnly, GetFormat(dstInfo.BytesPerPixel));
  109. GL.DispatchCompute((dstWidth + 31) / 32, (dstHeight + 31) / 32, 1);
  110. }
  111. Pipeline pipeline = (Pipeline)_renderer.Pipeline;
  112. pipeline.RestoreProgram();
  113. pipeline.RestoreImages1And2();
  114. DestroyViewIfNeeded(src, srcHandle);
  115. DestroyViewIfNeeded(dst, dstHandle);
  116. }
  117. public void CopyNonMSToMS(ITextureInfo src, ITextureInfo dst, int srcLayer, int dstLayer, int depth)
  118. {
  119. TextureCreateInfo srcInfo = src.Info;
  120. TextureCreateInfo dstInfo = dst.Info;
  121. int srcHandle = CreateViewIfNeeded(src);
  122. int dstHandle = CreateViewIfNeeded(dst);
  123. int srcWidth = srcInfo.Width;
  124. int srcHeight = srcInfo.Height;
  125. GL.UseProgram(GetNonMSToMSShader(srcInfo.BytesPerPixel));
  126. for (int z = 0; z < depth; z++)
  127. {
  128. GL.BindImageTexture(0, srcHandle, 0, false, srcLayer + z, TextureAccess.ReadOnly, GetFormat(srcInfo.BytesPerPixel));
  129. GL.BindImageTexture(1, dstHandle, 0, false, dstLayer + z, TextureAccess.WriteOnly, GetFormat(dstInfo.BytesPerPixel));
  130. GL.DispatchCompute((srcWidth + 31) / 32, (srcHeight + 31) / 32, 1);
  131. }
  132. Pipeline pipeline = (Pipeline)_renderer.Pipeline;
  133. pipeline.RestoreProgram();
  134. pipeline.RestoreImages1And2();
  135. DestroyViewIfNeeded(src, srcHandle);
  136. DestroyViewIfNeeded(dst, dstHandle);
  137. }
  138. private static SizedInternalFormat GetFormat(int bytesPerPixel)
  139. {
  140. return bytesPerPixel switch
  141. {
  142. 1 => SizedInternalFormat.R8ui,
  143. 2 => SizedInternalFormat.R16ui,
  144. 4 => SizedInternalFormat.R32ui,
  145. 8 => SizedInternalFormat.Rg32ui,
  146. 16 => SizedInternalFormat.Rgba32ui,
  147. _ => throw new ArgumentException($"Invalid bytes per pixel {bytesPerPixel}.")
  148. };
  149. }
  150. private static int CreateViewIfNeeded(ITextureInfo texture)
  151. {
  152. // Binding sRGB textures as images doesn't work on NVIDIA,
  153. // we need to create and bind a RGBA view for it to work.
  154. if (texture.Info.Format == Format.R8G8B8A8Srgb)
  155. {
  156. int handle = GL.GenTexture();
  157. GL.TextureView(
  158. handle,
  159. texture.Info.Target.Convert(),
  160. texture.Storage.Handle,
  161. PixelInternalFormat.Rgba8,
  162. texture.FirstLevel,
  163. 1,
  164. texture.FirstLayer,
  165. texture.Info.GetLayers());
  166. return handle;
  167. }
  168. return texture.Handle;
  169. }
  170. private static void DestroyViewIfNeeded(ITextureInfo info, int handle)
  171. {
  172. if (info.Handle != handle)
  173. {
  174. GL.DeleteTexture(handle);
  175. }
  176. }
  177. private int GetMSToNonMSShader(int bytesPerPixel)
  178. {
  179. return GetShader(ComputeShaderMSToNonMS, _msToNonMSProgramHandles, bytesPerPixel);
  180. }
  181. private int GetNonMSToMSShader(int bytesPerPixel)
  182. {
  183. return GetShader(ComputeShaderNonMSToMS, _nonMSToMSProgramHandles, bytesPerPixel);
  184. }
  185. private int GetShader(string code, int[] programHandles, int bytesPerPixel)
  186. {
  187. int index = BitOperations.Log2((uint)bytesPerPixel);
  188. if (programHandles[index] == 0)
  189. {
  190. int csHandle = GL.CreateShader(ShaderType.ComputeShader);
  191. string format = new[] { "r8ui", "r16ui", "r32ui", "rg32ui", "rgba32ui" }[index];
  192. GL.ShaderSource(csHandle, code.Replace("$FORMAT$", format));
  193. GL.CompileShader(csHandle);
  194. int programHandle = GL.CreateProgram();
  195. GL.AttachShader(programHandle, csHandle);
  196. GL.LinkProgram(programHandle);
  197. GL.DetachShader(programHandle, csHandle);
  198. GL.DeleteShader(csHandle);
  199. GL.GetProgram(programHandle, GetProgramParameterName.LinkStatus, out int status);
  200. if (status == 0)
  201. {
  202. throw new Exception(GL.GetProgramInfoLog(programHandle));
  203. }
  204. programHandles[index] = programHandle;
  205. }
  206. return programHandles[index];
  207. }
  208. public void Dispose()
  209. {
  210. for (int i = 0; i < _msToNonMSProgramHandles.Length; i++)
  211. {
  212. if (_msToNonMSProgramHandles[i] != 0)
  213. {
  214. GL.DeleteProgram(_msToNonMSProgramHandles[i]);
  215. _msToNonMSProgramHandles[i] = 0;
  216. }
  217. }
  218. for (int i = 0; i < _nonMSToMSProgramHandles.Length; i++)
  219. {
  220. if (_nonMSToMSProgramHandles[i] != 0)
  221. {
  222. GL.DeleteProgram(_nonMSToMSProgramHandles[i]);
  223. _nonMSToMSProgramHandles[i] = 0;
  224. }
  225. }
  226. }
  227. }
  228. }