ShaderManger.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253
  1. using System;
  2. using System.Collections.Generic;
  3. using System.IO;
  4. using System.Linq;
  5. using System.Net.Http.Headers;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. using Veldrid.SPIRV;
  9. namespace Veldrid.Common
  10. {
  11. internal class ShaderManger : IDisposable
  12. {
  13. private bool disposedValue;
  14. private Dictionary<String, Shader[]> AllShader = new Dictionary<String, Shader[]>();
  15. private Dictionary<String, Shader> OtherShader = new Dictionary<String, Shader>();
  16. private GraphicsDevice graphicsDevice;
  17. public ShaderManger(GraphicsDevice device)
  18. {
  19. if (device == null)
  20. {
  21. throw new ArgumentNullException(nameof(device));
  22. }
  23. if (graphicsDevice != null)
  24. {
  25. return;
  26. }
  27. graphicsDevice = device;
  28. foreach (var val in GLSLManger.Default.AllGLSL.Keys)
  29. {
  30. List<Shader> shaders = new List<Shader>();
  31. shaders.AddRange(graphicsDevice.ResourceFactory.CreateFromSpirv(GLSLManger.Default.AllGLSL[val].Vertex, GLSLManger.Default.AllGLSL[val].Fragment));
  32. if (GLSLManger.Default.AllGLSL[val].Compute.Stage == ShaderStages.Compute)
  33. {
  34. shaders.Add(graphicsDevice.ResourceFactory.CreateFromSpirv(GLSLManger.Default.AllGLSL[val].Compute));
  35. }
  36. //Shader frag = graphicsDevice.ResourceFactory.CreateShader(GLSLManger.Default.AllGLSL[val][1]);
  37. AllShader[val] = shaders.ToArray();
  38. }
  39. }
  40. /// <summary>
  41. /// 获取着色器
  42. /// </summary>
  43. /// <param name="name">着色器名</param>
  44. /// <param name="stages">着色器类型</param>
  45. /// <param name="entrypoint">着色器入口函数名</param>
  46. /// <returns></returns>
  47. /// <exception cref="ArgumentNullException">着色器名为空</exception>
  48. /// <exception cref="NotSupportedException">不支持的着色器类型</exception>
  49. public Shader GetOtherShader(string name,ShaderStages stages = ShaderStages.Geometry,string entrypoint= "main")
  50. {
  51. if (String.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name));
  52. if (OtherShader.TryGetValue(name, out var shader)) return shader;
  53. else
  54. {
  55. ShaderDescription description = new ShaderDescription(stages, GLSLManger.LoadShader(name), entrypoint);
  56. if (stages == ShaderStages.Compute)
  57. {
  58. var result = SpirvCompilation.CompileGlslToSpirv(Encoding.UTF8.GetString(description.ShaderBytes), "", stages,
  59. new GlslCompileOptions()
  60. {
  61. Debug = false
  62. });
  63. description.ShaderBytes = result.SpirvBytes;
  64. OtherShader[name] = graphicsDevice.ResourceFactory.CreateFromSpirv(description);
  65. }
  66. else
  67. {
  68. switch (graphicsDevice.BackendType)
  69. {
  70. case GraphicsBackend.Direct3D11:
  71. OtherShader[name] = graphicsDevice.ResourceFactory.CreateShader(description);
  72. break;
  73. default:
  74. {
  75. if (graphicsDevice.BackendType == GraphicsBackend.Metal && stages == ShaderStages.Geometry)
  76. {
  77. throw new NotSupportedException("Metal NotSupported Geometry Shader");
  78. }
  79. var result = SpirvCompilation.CompileGlslToSpirv(Encoding.UTF8.GetString(description.ShaderBytes), "", stages,
  80. new GlslCompileOptions()
  81. {
  82. Debug = false
  83. });
  84. description.ShaderBytes = result.SpirvBytes;
  85. OtherShader[name] = graphicsDevice.ResourceFactory.CreateFromSpirv(description);
  86. }
  87. break;
  88. }
  89. }
  90. return OtherShader[name];
  91. }
  92. }
  93. /// <summary>
  94. /// 获取着色器
  95. /// 获取顶点、片元和计算着色器,其他类型的着色器请使用<see cref="GetOtherShader(string, ShaderStages, string)"/>
  96. /// </summary>
  97. /// <param name="name">着色器资源名</param>
  98. /// <returns>系统中存在的着色器</returns>
  99. /// <exception cref="KeyNotFoundException">指定的着色器未找到</exception>
  100. public Shader[] GetShaders(string name)
  101. {
  102. var keys = AllShader.Keys.FirstOrDefault(x => x.IndexOf(name) >= 0);
  103. if (string.IsNullOrEmpty(keys))
  104. {
  105. throw new KeyNotFoundException(name);
  106. }
  107. return AllShader[keys];
  108. }
  109. public Shader GetLocalFileShader(string path,string entrypoint ="main", ShaderStages stages = ShaderStages.Vertex)
  110. {
  111. if (!File.Exists(path))
  112. {
  113. throw new FileNotFoundException(path);
  114. }
  115. if (OtherShader.TryGetValue(path, out var shader)) return shader;
  116. Byte[] buffer = File.ReadAllBytes(path);
  117. ShaderDescription description = new ShaderDescription(stages, buffer, entrypoint);
  118. var spirvresult = SpirvCompilation.CompileGlslToSpirv(System.Text.Encoding.UTF8.GetString(buffer), "", stages, new GlslCompileOptions()
  119. {
  120. Debug = false,
  121. });
  122. description.ShaderBytes = spirvresult.SpirvBytes;
  123. OtherShader[path] = graphicsDevice.ResourceFactory.CreateFromSpirv(description);
  124. return OtherShader[path];
  125. }
  126. protected virtual void Dispose(bool disposing)
  127. {
  128. if (!disposedValue)
  129. {
  130. if (disposing)
  131. {
  132. AllShader.Values.SelectMany(x => x).ToList().ForEach(x => x.Dispose());
  133. OtherShader.Values.ToList().ForEach(x => x.Dispose());
  134. AllShader.Clear();
  135. OtherShader.Clear();
  136. // TODO: 释放托管状态(托管对象)
  137. }
  138. // TODO: 释放未托管的资源(未托管的对象)并重写终结器
  139. // TODO: 将大型字段设置为 null
  140. disposedValue = true;
  141. }
  142. }
  143. // // TODO: 仅当“Dispose(bool disposing)”拥有用于释放未托管资源的代码时才替代终结器
  144. // ~ShaderManger()
  145. // {
  146. // // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
  147. // Dispose(disposing: false);
  148. // }
  149. public void Dispose()
  150. {
  151. // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
  152. Dispose(disposing: true);
  153. GC.SuppressFinalize(this);
  154. }
  155. }
  156. struct ShaderInfo
  157. {
  158. public ShaderDescription Vertex;
  159. public ShaderDescription Fragment;
  160. public ShaderDescription Compute;
  161. }
  162. internal class GLSLManger
  163. {
  164. public Dictionary<String, ShaderInfo> AllGLSL = new Dictionary<String, ShaderInfo>();
  165. private bool first = true;
  166. private GLSLManger()
  167. {
  168. }
  169. public void Init()
  170. {
  171. if (!first) return;
  172. var result = typeof(VeldridContent).Assembly.GetManifestResourceNames().Select(x =>
  173. {
  174. string[] strs = x.Split('.');
  175. return (string.Join('.', strs.Take(strs.Length - 1)), strs[^1]);
  176. }).Where(x => x.Item2.ToLower() == "vert" || x.Item2.ToLower() == "frag" || x.Item2.ToLower() == "comp").OrderByDescending(x => x.Item2).GroupBy(x => x.Item2).ToList();
  177. if (result.Count == 0) return;
  178. result.First(x=>x.Key == "vert").Select(x => x.Item1).Where(x => result.First(x=>x.Key == "frag").Select(y => y.Item1).Any(y => y == x)).ToList().ForEach(x =>
  179. {
  180. ShaderInfo shaderInfo = new ShaderInfo();
  181. var vertShader = new ShaderDescription(ShaderStages.Vertex, LoadShaderData(x + ".vert"), "main");
  182. var fragShader = new ShaderDescription(ShaderStages.Fragment, LoadShaderData(x + ".frag"), "main");
  183. var spirvresult = SpirvCompilation.CompileGlslToSpirv(System.Text.Encoding.UTF8.GetString(LoadShaderData(x + ".vert")), "", ShaderStages.Vertex, new GlslCompileOptions()
  184. {
  185. Debug = false,
  186. });
  187. vertShader.ShaderBytes = spirvresult.SpirvBytes;
  188. spirvresult = SpirvCompilation.CompileGlslToSpirv(System.Text.Encoding.UTF8.GetString(LoadShaderData(x + ".frag")), "", ShaderStages.Fragment, new GlslCompileOptions()
  189. {
  190. Debug = false,
  191. });
  192. fragShader.ShaderBytes = spirvresult.SpirvBytes;
  193. shaderInfo.Vertex = vertShader;
  194. shaderInfo.Fragment = fragShader;
  195. if (result.Any(y=>y.Key == "comp") && result.First(y => y.Key == "comp").Any(y => y.Item1.Contains(x)))
  196. {
  197. var computeShader = new ShaderDescription(ShaderStages.Compute, LoadShaderData(x + ".comp"), "main");
  198. spirvresult = SpirvCompilation.CompileGlslToSpirv(System.Text.Encoding.UTF8.GetString(LoadShaderData(x + ".comp")), "", ShaderStages.Compute, new GlslCompileOptions()
  199. {
  200. Debug = true,
  201. });
  202. computeShader.ShaderBytes = spirvresult.SpirvBytes;
  203. shaderInfo.Compute = computeShader;
  204. }
  205. if (result.Any(y=>y.Key =="geom") && result.First(y => y.Key == "geom").Any(y => y.Item1.Contains(x)))
  206. {
  207. var geometryShader = new ShaderDescription(ShaderStages.Geometry, LoadShaderData(x + ".geom"), "main");
  208. spirvresult = SpirvCompilation.CompileGlslToSpirv(System.Text.Encoding.UTF8.GetString(LoadShaderData(x + ".geom")), "", ShaderStages.Geometry, new GlslCompileOptions()
  209. {
  210. Debug = false,
  211. });
  212. geometryShader.ShaderBytes = spirvresult.SpirvBytes;
  213. shaderInfo.Compute = geometryShader;
  214. }
  215. AllGLSL[x] = shaderInfo;
  216. });
  217. first = false;
  218. }
  219. static GLSLManger()
  220. {
  221. }
  222. internal static byte[] LoadShader(string shadername)
  223. {
  224. if (string.IsNullOrEmpty(shadername)) throw new ArgumentNullException(nameof(shadername));
  225. string path = typeof(VeldridContent).Assembly.GetManifestResourceNames().FirstOrDefault(x => x.Contains(shadername));
  226. if (string.IsNullOrEmpty(path)) throw new KeyNotFoundException(nameof(shadername));
  227. return LoadShaderData(path);
  228. }
  229. static byte[] LoadShaderData(string respath)
  230. {
  231. using (var stream =typeof(VeldridContent).Assembly.GetManifestResourceStream(respath))
  232. {
  233. byte[] buffer = new byte[stream.Length];
  234. stream.Position = 0;
  235. stream.Read(buffer, 0, buffer.Length);
  236. return buffer;
  237. }
  238. }
  239. public static GLSLManger Default { get; } = new GLSLManger();
  240. }
  241. }