StashRenderer.cs 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. using FontStashSharp.Interfaces;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.Linq;
  5. using System.Text;
  6. using System.Threading.Tasks;
  7. using Vulkan;
  8. using System.Runtime.CompilerServices;
  9. using System.Numerics;
  10. using System.Drawing;
  11. namespace Veldrid.Common
  12. {
  13. internal class StashTextureManger : ITexture2DManager
  14. {
  15. Texture lastTexure;
  16. private GraphicsDevice _Graphics;
  17. public StashTextureManger(GraphicsDevice graphics)
  18. {
  19. _Graphics = graphics;
  20. }
  21. public Veldrid.Texture CreateTexture(int width, int height)
  22. {
  23. if (lastTexure == null || lastTexure.Width != width || lastTexure.Height != height)
  24. {
  25. lastTexure?.Dispose();
  26. lastTexure = _Graphics.ResourceFactory.CreateTexture(new TextureDescription((uint)width, (uint)height, 1, 1, 1, PixelFormat.R8_G8_B8_A8_UNorm, TextureUsage.Sampled, TextureType.Texture2D, TextureSampleCount.Count1));
  27. }
  28. return lastTexure;
  29. }
  30. public Size GetTextureSize(Veldrid.Texture texture)
  31. {
  32. var t = (Texture)texture;
  33. return new Size((Int32)t.Width, (Int32)t.Height);
  34. }
  35. public void SetTextureData(Veldrid.Texture texture, Rectangle bounds, byte[] data)
  36. {
  37. if(texture is Texture t)
  38. {
  39. _Graphics.UpdateTexture(t, data, (UInt32)bounds.X, (UInt32)bounds.Y, 0, (UInt32)bounds.Width, (UInt32)bounds.Height, 1, 0, 0);
  40. }
  41. }
  42. }
  43. internal class StashRenderer : IFontStashRenderer2,IDisposable
  44. {
  45. GraphicsDevice graphicsDevice;
  46. private const int MAX_SPRITES = 256;
  47. private const int MAX_VERTICES = MAX_SPRITES * 4;
  48. private const int MAX_INDICES = MAX_SPRITES * 6;
  49. private VertexPositionColorTexture[] _vertexData = new VertexPositionColorTexture[MAX_VERTICES];
  50. private Shader[] shaders;
  51. private CommandList _commandList;
  52. private DeviceBuffer _vertexBuffer;
  53. private DeviceBuffer _backColorBuffer;
  54. private DeviceBuffer _indexBuffer;
  55. private DeviceBuffer _matrixBuffer;
  56. private ResourceLayout _matrixLayout;
  57. private ResourceLayout _backColotLayout;
  58. private ResourceSet _matrixSet;
  59. private ResourceSet _backColorSet;
  60. private ResourceLayout _textureLayout;
  61. private ResourceSet _textureSet;
  62. private Pipeline _pipeline;
  63. private Pipeline _backColorPipline;
  64. private System.Numerics.Matrix4x4 Matrix { get; set; }
  65. private ushort[] _indexData;
  66. private Veldrid.Texture _lastTexture;
  67. private int _vertexIndex = 0;
  68. public StashRenderer(GraphicsDevice device,CommandList commandList, Shader[] textshader, Shader[] backColorshader,BlendStateDescription textBlend, BlendStateDescription backblendState)
  69. {
  70. graphicsDevice = device;
  71. _commandList = commandList;
  72. Matrix = System.Numerics.Matrix4x4.CreateOrthographicOffCenter(0, 1024, 1024, 0, 0, -1);
  73. _indexData = GenerateIndexArray();
  74. _vertexBuffer = graphicsDevice.ResourceFactory.CreateBuffer(new BufferDescription((UInt32)(Unsafe.SizeOf<VertexPositionColorTexture>() * _vertexData.Length), BufferUsage.VertexBuffer));
  75. _indexBuffer = graphicsDevice.ResourceFactory.CreateBuffer(new BufferDescription((UInt32)(Unsafe.SizeOf<short>() * _indexData.Length), BufferUsage.IndexBuffer));
  76. shaders = textshader;
  77. var vertexLayout = new VertexLayoutDescription(
  78. new VertexElementDescription("a_position", VertexElementSemantic.TextureCoordinate, VertexElementFormat.Float3),
  79. new VertexElementDescription("a_color", VertexElementSemantic.TextureCoordinate, VertexElementFormat.Float4),
  80. new VertexElementDescription("a_texCoords0", VertexElementSemantic.TextureCoordinate, VertexElementFormat.Float2));
  81. _matrixBuffer = graphicsDevice.ResourceFactory.CreateBuffer(new BufferDescription((UInt32)(Unsafe.SizeOf<System.Numerics.Matrix4x4>()), BufferUsage.UniformBuffer));
  82. _matrixLayout = graphicsDevice.ResourceFactory.CreateResourceLayout(new ResourceLayoutDescription(new ResourceLayoutElementDescription("a_MatrixTransform", ResourceKind.UniformBuffer, ShaderStages.Vertex)));
  83. _matrixSet = graphicsDevice.ResourceFactory.CreateResourceSet(new ResourceSetDescription(_matrixLayout, _matrixBuffer));
  84. _backColorBuffer = graphicsDevice.ResourceFactory.CreateBuffer(new BufferDescription((uint)Unsafe.SizeOf<RgbaFloat>(), BufferUsage.UniformBuffer));
  85. _backColotLayout = graphicsDevice.ResourceFactory.CreateResourceLayout(new ResourceLayoutDescription(new ResourceLayoutElementDescription("a_color", ResourceKind.UniformBuffer, ShaderStages.Fragment)));
  86. _backColorSet = graphicsDevice.ResourceFactory.CreateResourceSet(new ResourceSetDescription(_backColotLayout, _backColorBuffer));
  87. _textureLayout = graphicsDevice.ResourceFactory.CreateResourceLayout(
  88. new ResourceLayoutDescription(
  89. new ResourceLayoutElementDescription("Texture", ResourceKind.TextureReadOnly, ShaderStages.Fragment),
  90. new ResourceLayoutElementDescription("TextureSampler", ResourceKind.Sampler, ShaderStages.Fragment)
  91. ));
  92. texture2DManager = new StashTextureManger(graphicsDevice);
  93. GraphicsPipelineDescription pipelineDescription = new GraphicsPipelineDescription();
  94. pipelineDescription.BlendState = textBlend;
  95. pipelineDescription.DepthStencilState = new DepthStencilStateDescription(
  96. depthTestEnabled: true,
  97. depthWriteEnabled: true,
  98. comparisonKind: ComparisonKind.GreaterEqual);
  99. pipelineDescription.RasterizerState = new RasterizerStateDescription(
  100. cullMode: FaceCullMode.Back,
  101. fillMode: PolygonFillMode.Solid,
  102. frontFace: FrontFace.Clockwise,
  103. depthClipEnabled: true,
  104. scissorTestEnabled: false);
  105. pipelineDescription.PrimitiveTopology = PrimitiveTopology.TriangleList;
  106. pipelineDescription.ResourceLayouts = new ResourceLayout[] {_matrixLayout,_textureLayout };
  107. pipelineDescription.ShaderSet = new ShaderSetDescription(
  108. vertexLayouts: new VertexLayoutDescription[] {vertexLayout },
  109. shaders: shaders,
  110. specializations: new[] { new SpecializationConstant(0,graphicsDevice.IsClipSpaceYInverted) });
  111. pipelineDescription.Outputs = graphicsDevice.SwapchainFramebuffer.OutputDescription;
  112. _pipeline = graphicsDevice.ResourceFactory.CreateGraphicsPipeline(pipelineDescription);
  113. _backColorPipline = graphicsDevice.ResourceFactory.CreateGraphicsPipeline(new GraphicsPipelineDescription()
  114. {
  115. BlendState = backblendState,
  116. DepthStencilState = new DepthStencilStateDescription()
  117. {
  118. DepthTestEnabled= true,
  119. DepthWriteEnabled= true,
  120. DepthComparison = ComparisonKind.LessEqual
  121. },
  122. RasterizerState = new RasterizerStateDescription()
  123. {
  124. CullMode = FaceCullMode.Back,
  125. FillMode = PolygonFillMode.Solid,
  126. FrontFace = FrontFace.Clockwise,
  127. DepthClipEnabled= true,
  128. ScissorTestEnabled = false,
  129. },
  130. PrimitiveTopology= PrimitiveTopology.TriangleStrip,
  131. ResourceLayouts = new ResourceLayout[] {_matrixLayout,_backColotLayout },
  132. ShaderSet = new ShaderSetDescription()
  133. {
  134. Shaders = backColorshader,
  135. Specializations = new[] {new SpecializationConstant(0,graphicsDevice.IsClipSpaceYInverted) },
  136. VertexLayouts = new VertexLayoutDescription[] { vertexLayout},
  137. },
  138. Outputs = graphicsDevice.SwapchainFramebuffer.OutputDescription,
  139. });
  140. }
  141. private ushort[] GenerateIndexArray()
  142. {
  143. ushort[] result = new ushort[MAX_INDICES];
  144. for (int i = 0, j = 0; i < MAX_INDICES; i += 6, j += 4)
  145. {
  146. result[i] = (ushort)(j);
  147. result[i + 1] = (ushort)(j + 1);
  148. result[i + 2] = (ushort)(j + 2);
  149. result[i + 3] = (ushort)(j + 3);
  150. result[i + 4] = (ushort)(j + 2);
  151. result[i + 5] = (ushort)(j + 1);
  152. }
  153. return result;
  154. }
  155. public RgbaFloat BackColor { get; set; } = RgbaFloat.Clear;
  156. public void Begin()
  157. {
  158. }
  159. private ITexture2DManager texture2DManager;
  160. private bool disposedValue;
  161. internal Texture Texture => _lastTexture;
  162. ITexture2DManager IFontStashRenderer2.TextureManager => texture2DManager;
  163. unsafe void IFontStashRenderer2.DrawQuad(Veldrid.Texture texture, ref VertexPositionColorTexture topLeft, ref VertexPositionColorTexture topRight, ref VertexPositionColorTexture bottomLeft, ref VertexPositionColorTexture bottomRight)
  164. {
  165. if (_lastTexture != texture)
  166. {
  167. FlushBuffer();
  168. }
  169. _vertexData[_vertexIndex++] = topLeft;
  170. _vertexData[_vertexIndex++] = topRight;
  171. _vertexData[_vertexIndex++] = bottomLeft;
  172. _vertexData[_vertexIndex++] = bottomRight;
  173. _lastTexture = texture;
  174. }
  175. private unsafe void FlushBuffer()
  176. {
  177. if(_vertexIndex ==0|| _lastTexture ==null)
  178. {
  179. return;
  180. }
  181. if(_textureSet ==null)
  182. {
  183. _textureSet = graphicsDevice.ResourceFactory.CreateResourceSet(new ResourceSetDescription(_textureLayout, (Texture)_lastTexture, graphicsDevice.LinearSampler));
  184. }
  185. //
  186. uint count = (UInt32)_vertexIndex * 6 / 4;
  187. if (BackColor.A > 0)
  188. {
  189. _commandList.UpdateBuffer(_backColorBuffer, 0, BackColor);
  190. var rectdata = _indexData.Take((int)count).Distinct().Select(x => _vertexData[x]);
  191. RectangleF rec = new RectangleF();
  192. rec.X = rectdata.Min(x => x.Position.X) - 2;
  193. rec.Y = rectdata.Min(y => y.Position.Y) - 2;
  194. rec.Width = rectdata.Max(x => x.Position.X) - rec.X + 2;
  195. rec.Height = rectdata.Max(y => y.Position.Y) - rec.Y + 2;
  196. if (BackColorFixedSize.Width > 0 && BackColorFixedSize.Height > 0)
  197. {
  198. rec.Width = BackColorFixedSize.Width;
  199. rec.Height = BackColorFixedSize.Height;
  200. }
  201. VertexPositionColorTexture[] temp = new VertexPositionColorTexture[4];
  202. temp[0].Position = new Vector3(rec.X, rec.Y, _vertexData[0].Position.Z);
  203. temp[1].Position = new Vector3(rec.X + rec.Width, rec.Y, _vertexData[0].Position.Z);
  204. temp[2].Position = new Vector3(rec.X, rec.Y + rec.Height, _vertexData[0].Position.Z);
  205. temp[3].Position = new Vector3(rec.X + rec.Width, rec.Y + rec.Height, _vertexData[0].Position.Z);
  206. _commandList.UpdateBuffer(_vertexBuffer, 0, temp);
  207. //_commandList.UpdateBuffer(_indexBuffer, 0, backcolorindex);
  208. _commandList.SetPipeline(_backColorPipline);
  209. _commandList.SetVertexBuffer(0, _vertexBuffer);
  210. //_commandList.SetIndexBuffer(_indexBuffer, IndexFormat.UInt16);
  211. _commandList.SetGraphicsResourceSet(0, _matrixSet);
  212. _commandList.SetGraphicsResourceSet(1, _backColorSet);
  213. _commandList.Draw(4);
  214. }
  215. _commandList.UpdateBuffer(_matrixBuffer, 0, Matrix);
  216. _commandList.UpdateBuffer(_indexBuffer, 0, _indexData);
  217. _commandList.UpdateBuffer(_vertexBuffer, 0, _vertexData);
  218. _commandList.SetPipeline(_pipeline);
  219. _commandList.SetVertexBuffer(0, _vertexBuffer);
  220. _commandList.SetIndexBuffer(_indexBuffer, IndexFormat.UInt16);
  221. _commandList.SetGraphicsResourceSet(0, _matrixSet);
  222. _commandList.SetGraphicsResourceSet(1, _textureSet);
  223. _commandList.DrawIndexed(count, 1, 0, 0, 0);
  224. _vertexIndex = 0;
  225. }
  226. public SizeF BackColorFixedSize { get; set; } = SizeF.Empty;
  227. public void End()
  228. {
  229. Matrix =Matrix4x4.CreateOrthographicOffCenter(0,graphicsDevice.MainSwapchain.Framebuffer.Width,graphicsDevice.MainSwapchain.Framebuffer.Height,0,0,-1);
  230. FlushBuffer();
  231. }
  232. public void End(Matrix4x4 matrix)
  233. {
  234. Matrix= matrix;
  235. FlushBuffer();
  236. }
  237. protected virtual void Dispose(bool disposing)
  238. {
  239. if (!disposedValue)
  240. {
  241. if (disposing)
  242. {
  243. _indexData = new UInt16[0];
  244. _vertexData = new VertexPositionColorTexture[0];
  245. //foreach (var val in shaders) val?.Dispose();
  246. _vertexBuffer?.Dispose();
  247. _indexBuffer?.Dispose();
  248. (_lastTexture as Texture)?.Dispose();
  249. _matrixBuffer?.Dispose();
  250. _matrixSet?.Dispose();
  251. _pipeline?.Dispose();
  252. _textureLayout?.Dispose();
  253. _textureSet?.Dispose();
  254. _backColorBuffer?.Dispose();
  255. _backColorPipline?.Dispose();
  256. _backColorSet?.Dispose();
  257. _backColotLayout?.Dispose();
  258. // TODO: 释放托管状态(托管对象)
  259. }
  260. // TODO: 释放未托管的资源(未托管的对象)并重写终结器
  261. // TODO: 将大型字段设置为 null
  262. disposedValue = true;
  263. }
  264. }
  265. // // TODO: 仅当“Dispose(bool disposing)”拥有用于释放未托管资源的代码时才替代终结器
  266. // ~StashRenderer()
  267. // {
  268. // // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
  269. // Dispose(disposing: false);
  270. // }
  271. public void Dispose()
  272. {
  273. // 不要更改此代码。请将清理代码放入“Dispose(bool disposing)”方法中
  274. Dispose(disposing: true);
  275. GC.SuppressFinalize(this);
  276. }
  277. }
  278. }