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. using Veldrid.Windows.Plot;
  10. namespace Veldrid.Common
  11. {
  12. internal class ShaderManger : IDisposable
  13. {
  14. private bool disposedValue;
  15. private Dictionary<String, Shader[]> AllShader = new Dictionary<String, Shader[]>();
  16. private Dictionary<String, Shader> OtherShader = new Dictionary<String, Shader>();
  17. private GraphicsDevice graphicsDevice;
  18. public ShaderManger(GraphicsDevice device)
  19. {
  20. if (device == null)
  21. {
  22. throw new ArgumentNullException(nameof(device));
  23. }
  24. if (graphicsDevice != null)
  25. {
  26. return;
  27. }
  28. graphicsDevice = device;
  29. foreach (var val in GLSLManger.Default.AllGLSL.Keys)
  30. {
  31. List<Shader> shaders = new List<Shader>();
  32. shaders.AddRange(graphicsDevice.ResourceFactory.CreateFromSpirv(GLSLManger.Default.AllGLSL[val].Vertex, GLSLManger.Default.AllGLSL[val].Fragment));
  33. if (GLSLManger.Default.AllGLSL[val].Compute.Stage == ShaderStages.Compute)
  34. {
  35. shaders.Add(graphicsDevice.ResourceFactory.CreateFromSpirv(GLSLManger.Default.AllGLSL[val].Compute));
  36. }
  37. //Shader frag = graphicsDevice.ResourceFactory.CreateShader(GLSLManger.Default.AllGLSL[val][1]);
  38. AllShader[val] = shaders.ToArray();
  39. }
  40. }
  41. /// <summary>
  42. /// 获取着色器
  43. /// </summary>
  44. /// <param name="name">着色器名</param>
  45. /// <param name="stages">着色器类型</param>
  46. /// <param name="entrypoint">着色器入口函数名</param>
  47. /// <returns></returns>
  48. /// <exception cref="ArgumentNullException">着色器名为空</exception>
  49. /// <exception cref="NotSupportedException">不支持的着色器类型</exception>
  50. public Shader GetOtherShader(string name,ShaderStages stages = ShaderStages.Geometry,string entrypoint= "main")
  51. {
  52. if (String.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name));
  53. if (OtherShader.TryGetValue(name, out var shader)) return shader;
  54. else
  55. {
  56. ShaderDescription description = new ShaderDescription(stages, GLSLManger.LoadShader(name), entrypoint);
  57. if (stages == ShaderStages.Compute)
  58. {
  59. var result = SpirvCompilation.CompileGlslToSpirv(Encoding.UTF8.GetString(description.ShaderBytes), "", stages,
  60. new GlslCompileOptions()
  61. {
  62. Debug = false
  63. });
  64. description.ShaderBytes = result.SpirvBytes;
  65. OtherShader[name] = graphicsDevice.ResourceFactory.CreateFromSpirv(description);
  66. }
  67. else
  68. {
  69. switch (graphicsDevice.BackendType)
  70. {
  71. case GraphicsBackend.Direct3D11:
  72. OtherShader[name] = graphicsDevice.ResourceFactory.CreateShader(description);
  73. break;
  74. default:
  75. {
  76. if (graphicsDevice.BackendType == GraphicsBackend.Metal && stages == ShaderStages.Geometry)
  77. {
  78. throw new NotSupportedException("Metal NotSupported Geometry Shader");
  79. }
  80. var result = SpirvCompilation.CompileGlslToSpirv(Encoding.UTF8.GetString(description.ShaderBytes), "", stages,
  81. new GlslCompileOptions()
  82. {
  83. Debug = false
  84. });
  85. description.ShaderBytes = result.SpirvBytes;
  86. OtherShader[name] = graphicsDevice.ResourceFactory.CreateFromSpirv(description);
  87. }
  88. break;
  89. }
  90. }
  91. return OtherShader[name];
  92. }
  93. }
  94. /// <summary>
  95. /// 获取着色器
  96. /// 获取顶点、片元和计算着色器,其他类型的着色器请使用<see cref="GetOtherShader(string, ShaderStages, string)"/>
  97. /// </summary>
  98. /// <param name="name">着色器资源名</param>
  99. /// <returns>系统中存在的着色器</returns>
  100. /// <exception cref="KeyNotFoundException">指定的着色器未找到</exception>
  101. public Shader[] GetShaders(string name)
  102. {
  103. var keys = AllShader.Keys.FirstOrDefault(x => x.IndexOf(name) >= 0);
  104. if (string.IsNullOrEmpty(keys))
  105. {
  106. throw new KeyNotFoundException(name);
  107. }
  108. return AllShader[keys];
  109. }
  110. public Shader GetLocalFileShader(string path,string entrypoint ="main", ShaderStages stages = ShaderStages.Vertex)
  111. {
  112. if (!File.Exists(path))
  113. {
  114. throw new FileNotFoundException(path);
  115. }
  116. if (OtherShader.TryGetValue(path, out var shader)) return shader;
  117. Byte[] buffer = File.ReadAllBytes(path);
  118. ShaderDescription description = new ShaderDescription(stages, buffer, entrypoint);
  119. var spirvresult = SpirvCompilation.CompileGlslToSpirv(System.Text.Encoding.UTF8.GetString(buffer), "", stages, new GlslCompileOptions()
  120. {
  121. Debug = false,
  122. });
  123. description.ShaderBytes = spirvresult.SpirvBytes;
  124. OtherShader[path] = graphicsDevice.ResourceFactory.CreateFromSpirv(description);
  125. return OtherShader[path];
  126. }
  127. protected virtual void Dispose(bool disposing)
  128. {
  129. if (!disposedValue)
  130. {
  131. if (disposing)
  132. {
  133. AllShader.Values.SelectMany(x => x).ToList().ForEach(x => x.Dispose());
  134. OtherShader.Values.ToList().ForEach(x => x.Dispose());
  135. AllShader.Clear();
  136. OtherShader.Clear();
  137. // TODO: 释放托管状态(托管对象)
  138. }
  139. // TODO: 释放未托管的资源(未托管的对象)并重写终结器
  140. // TODO: 将大型字段设置为 null
  141. disposedValue = true;
  142. }
  143. }
  144. // // TODO: 仅当“Dispose(bool disposing)”拥有用于释放未托管资源的代码时才替代终结器
  145. // ~ShaderManger()
  146. // {
  147. // // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
  148. // Dispose(disposing: false);
  149. // }
  150. public void Dispose()
  151. {
  152. // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
  153. Dispose(disposing: true);
  154. GC.SuppressFinalize(this);
  155. }
  156. }
  157. struct ShaderInfo
  158. {
  159. public ShaderDescription Vertex;
  160. public ShaderDescription Fragment;
  161. public ShaderDescription Compute;
  162. }
  163. internal class GLSLManger
  164. {
  165. public Dictionary<String, ShaderInfo> AllGLSL = new Dictionary<String, ShaderInfo>();
  166. private bool first = true;
  167. private GLSLManger()
  168. {
  169. }
  170. public void Init()
  171. {
  172. if (!first) return;
  173. var result = typeof(IVeldridContent).Assembly.GetManifestResourceNames().Select(x =>
  174. {
  175. string[] strs = x.Split('.');
  176. return (string.Join('.', strs.Take(strs.Length - 1)), strs[^1]);
  177. }).Where(x => x.Item2.ToLower() == "vert" || x.Item2.ToLower() == "frag" || x.Item2.ToLower() == "comp").OrderByDescending(x => x.Item2).GroupBy(x => x.Item2).ToList();
  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 = false,
  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(IVeldridContent).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(IVeldridContent).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. }