LineSeries.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Linq;
  5. using System.Net.Http.Headers;
  6. using System.Numerics;
  7. using System.Runtime.CompilerServices;
  8. using System.Runtime.InteropServices;
  9. using System.Security.Cryptography;
  10. using System.Text;
  11. namespace Veldrid.Common.Plot
  12. {
  13. public class LineSeries: BaseVeldridRender,IZoomRender
  14. {
  15. public Vector2 WindowScale { get; set; } = Vector2.One;
  16. public float HScale { get; set; } = 1;
  17. public float VScale { get; set; } = 1;
  18. public float HOffset { get; set; }
  19. public float VOffset { get; set; }
  20. public bool ZoomEnbled { get; set; }
  21. private const uint ThreadGroupSizeX = 1000;
  22. private ProjView projView;
  23. Pipeline pipeline;
  24. private PlotInfo plotInfo;
  25. DeviceBuffer plotInfoBuffer;
  26. DeviceBuffer projViewBuffer;
  27. DeviceBuffer dataBuffer;
  28. ResourceLayout dataLayout;
  29. ResourceSet dataSet;
  30. ResourceLayout infoLayout;
  31. ResourceSet infoSet;
  32. Shader[] shaders;
  33. DeviceBuffer resultBuffer;
  34. DeviceBuffer cpuBuffer;
  35. ResourceLayout computeLayout;
  36. ResourceSet computeSet;
  37. Pipeline computePipline;
  38. ResourceLayout computeLineInfoLayout;
  39. ResourceSet computeLineInfoSet;
  40. Shader computeShader;
  41. CommandList computeCommandList;
  42. private object locker = new object();
  43. public LineSeries(VeldridContent content, uint datalen=1000,uint plotcount=4):base(content)
  44. {
  45. dataLenght = datalen;
  46. PlotInfos = new SeriesInfo[plotcount];
  47. Margin = new Padding(40, 10, 10, 20);
  48. }
  49. internal override void DisposeResources()
  50. {
  51. base.DisposeResources();
  52. pipeline?.Dispose();
  53. plotInfoBuffer?.Dispose();
  54. projViewBuffer?.Dispose();
  55. dataBuffer?.Dispose();
  56. dataLayout?.Dispose();
  57. dataSet?.Dispose();
  58. infoLayout?.Dispose();
  59. infoSet?.Dispose();
  60. resultBuffer?.Dispose();
  61. cpuBuffer?.Dispose();
  62. computeLayout?.Dispose();
  63. computeSet?.Dispose();
  64. computePipline?.Dispose();
  65. computeCommandList?.Dispose();
  66. computeLineInfoLayout?.Dispose();
  67. computeLineInfoSet?.Dispose();
  68. computeShader?.Dispose();
  69. }
  70. private void CreateDataBuffer()
  71. {
  72. if (DataLenght == 0 || PlotInfos ==null|| PlotInfos.Length == 0) return;
  73. lock (locker)
  74. {
  75. dataBuffer?.Dispose();
  76. pipeline?.Dispose();
  77. dataBuffer = ResourceFactory.CreateBuffer(new BufferDescription()
  78. {
  79. SizeInBytes = (uint)(DataLenght * PlotInfos.Length * 4),
  80. Usage = BufferUsage.StructuredBufferReadWrite,
  81. StructureByteStride = 4,
  82. });
  83. dataSet = ResourceFactory.CreateResourceSet(new ResourceSetDescription(dataLayout, dataBuffer));
  84. pipeline = CreatePipLine(PrimitiveTopology.LineStrip, new ResourceLayout[] { dataLayout, infoLayout }, new VertexLayoutDescription[0],new[] { shaders[0], shaders[1] });
  85. datastartindex = 0;
  86. datatotallen = 0;
  87. TotalCount = 0;
  88. MaxAndMin = new Vector2[PlotInfos.Length];
  89. CreateComputeBuffer();
  90. }
  91. }
  92. internal override void CreateResources()
  93. {
  94. base.CreateResources();
  95. plotInfoBuffer = ResourceFactory.CreateBuffer(new BufferDescription()
  96. {
  97. SizeInBytes = (uint)Unsafe.SizeOf<PlotInfo>(),
  98. Usage = BufferUsage.UniformBuffer,
  99. });
  100. projViewBuffer = ResourceFactory.CreateBuffer(new BufferDescription()
  101. {
  102. SizeInBytes = (uint)Unsafe.SizeOf<ProjView>(),
  103. Usage = BufferUsage.UniformBuffer ,
  104. });
  105. datatotallen = 0;
  106. datastartindex = 0;
  107. shaders = CreateShader("LineSeries");
  108. dataLayout = ResourceFactory.CreateResourceLayout(new ResourceLayoutDescription(new ResourceLayoutElementDescription()
  109. {
  110. Name = "DataBuffer",
  111. Stages = ShaderStages.Vertex,
  112. Kind = ResourceKind.StructuredBufferReadOnly,
  113. }));
  114. infoLayout = ResourceFactory.CreateResourceLayout(new ResourceLayoutDescription(
  115. new ResourceLayoutElementDescription()
  116. {
  117. Name = "InfoBuffer",
  118. Kind = ResourceKind.UniformBuffer,
  119. Stages = ShaderStages.Vertex,
  120. },
  121. new ResourceLayoutElementDescription()
  122. {
  123. Name = "ProjView",
  124. Kind = ResourceKind.UniformBuffer,
  125. Stages = ShaderStages.Vertex,
  126. }));
  127. infoSet = ResourceFactory.CreateResourceSet(new ResourceSetDescription(infoLayout, plotInfoBuffer, projViewBuffer));
  128. resultBuffer = ResourceFactory.CreateBuffer(new BufferDescription(20 * 4, BufferUsage.StructuredBufferReadWrite, 4));
  129. cpuBuffer = ResourceFactory.CreateBuffer(new BufferDescription(resultBuffer.SizeInBytes, BufferUsage.Staging));
  130. computeLayout = ResourceFactory.CreateResourceLayout(new ResourceLayoutDescription(
  131. new ResourceLayoutElementDescription("DataBuffer", ResourceKind.StructuredBufferReadOnly, ShaderStages.Compute),
  132. new ResourceLayoutElementDescription("ResultDataBuffer", ResourceKind.StructuredBufferReadWrite, ShaderStages.Compute)));
  133. computeLineInfoLayout = ResourceFactory.CreateResourceLayout(new ResourceLayoutDescription(
  134. new ResourceLayoutElementDescription("InfoBuffer", ResourceKind.UniformBuffer, ShaderStages.Compute)));
  135. computeLineInfoSet = ResourceFactory.CreateResourceSet(new ResourceSetDescription(computeLineInfoLayout, plotInfoBuffer));
  136. ShaderDescription shaderDescription = new ShaderDescription(ShaderStages.Compute, GLSLManger.LoadShader("LineSeries.hlsl"), "main")
  137. {
  138. Debug = true,
  139. };
  140. computeShader = ResourceFactory.CreateShader(shaderDescription);
  141. computeCommandList = ResourceFactory.CreateCommandList() ;
  142. CreateDataBuffer();
  143. }
  144. private void CreateComputeBuffer()
  145. {
  146. computeSet?.Dispose();
  147. computePipline?.Dispose();
  148. computeSet = ResourceFactory.CreateResourceSet(new ResourceSetDescription(computeLayout, dataBuffer, resultBuffer));
  149. computePipline = ResourceFactory.CreateComputePipeline(new ComputePipelineDescription(computeShader, new[] { computeLayout, computeLineInfoLayout }, ThreadGroupSizeX, 1, 1));
  150. }
  151. struct PlotInfo
  152. {
  153. public RgbaFloat Color;
  154. public uint PlotIndex;
  155. public float Interval;
  156. public uint DataStartIndex;
  157. public uint PlotDataLenght;
  158. }
  159. struct ProjView
  160. {
  161. public Matrix4x4 Proj;
  162. public Matrix4x4 View;
  163. }
  164. public void Clear()
  165. {
  166. datastartindex = 0;
  167. datatotallen = 0;
  168. TotalCount = 0;
  169. }
  170. public ulong TotalCount { get; private set; }
  171. public Vector2[] MaxAndMin { get; private set; } = new Vector2[0];
  172. public unsafe void AddData(float[] data)
  173. {
  174. if (DataLenght == 0 || PlotInfos == null || PlotInfos.Length == 0) return;
  175. if (data == null|| data.Length!=PlotInfos.Length) return;
  176. TotalCount++;
  177. for(int i=0;i<data.Length;i++)
  178. {
  179. GraphicsDevice.UpdateBuffer(dataBuffer,(uint)((datastartindex+i*DataLenght)*Unsafe.SizeOf<float>()),ref data[i],(uint)Unsafe.SizeOf<float>());
  180. }
  181. datastartindex++;
  182. datatotallen++;
  183. if(datatotallen>DataLenght)datatotallen = DataLenght;
  184. if (datastartindex >= DataLenght) datastartindex = 0;
  185. MaxAndMin = new Vector2[PlotInfos.Length];
  186. //return;
  187. if (datatotallen > 0)
  188. {
  189. computeCommandList.Begin();
  190. CalcMaxMin(computeCommandList);
  191. computeCommandList.End();
  192. GraphicsDevice.SubmitCommands(computeCommandList);
  193. GraphicsDevice.WaitForIdle();
  194. }
  195. }
  196. private unsafe void CalcMaxMin(CommandList command)
  197. {
  198. MaxAndMin = new Vector2[PlotInfos.Length];
  199. plotInfo.DataStartIndex = datatotallen;
  200. plotInfo.PlotDataLenght = DataLenght;
  201. command.SetPipeline(computePipline);
  202. command.SetComputeResourceSet(0, computeSet);
  203. command.SetComputeResourceSet(1, computeLineInfoSet);
  204. for (uint i = 0; i < PlotInfos.Length; i++)
  205. {
  206. plotInfo.PlotIndex = i;
  207. command.UpdateBuffer(plotInfoBuffer, 0, plotInfo);
  208. command.Dispatch((uint)MathF.Ceiling(((float)datatotallen) / ThreadGroupSizeX), 1, 1);
  209. }
  210. command.CopyBuffer(resultBuffer, 0, cpuBuffer, 0, (uint)(MaxAndMin.Length * Unsafe.SizeOf<Vector2>()));
  211. var mapped = GraphicsDevice.Map(cpuBuffer, MapMode.ReadWrite);
  212. Unsafe.CopyBlock(ref Unsafe.As<Vector2, byte>(ref MaxAndMin[0]), ref Unsafe.AsRef<byte>(mapped.Data.ToPointer()), (uint)(MaxAndMin.Length * Unsafe.SizeOf<Vector2>()));
  213. GraphicsDevice.Unmap(cpuBuffer);
  214. }
  215. internal unsafe override void DrawData()
  216. {
  217. if (DataLenght == 0 || PlotInfos == null || PlotInfos.Length == 0) return;
  218. lock (locker)
  219. {
  220. base.DrawData();
  221. if (datatotallen == 0) return;
  222. //CalcMaxMin(CommandList);
  223. projView.Proj = OrthographicMatrix;
  224. projView.View = GetLineMatrix(HScale,VScale,0,VOffset);
  225. CommandList.SetFramebuffer(MainSwapchainBuffer);
  226. CommandList.UpdateBuffer(projViewBuffer, 0, projView);
  227. CommandList.UpdateBuffer(plotInfoBuffer, 0, plotInfo);
  228. CommandList.SetPipeline(pipeline);
  229. CommandList.SetGraphicsResourceSet(0, dataSet);
  230. CommandList.SetGraphicsResourceSet(1, infoSet);
  231. for (uint i = 0; i < PlotInfos.Length; i++)
  232. {
  233. if (!PlotInfos[i].Visibily) continue;
  234. plotInfo.Color = PlotInfos[i].Color;
  235. plotInfo.PlotDataLenght = DataLenght;
  236. plotInfo.DataStartIndex = datatotallen == DataLenght ? datastartindex : 0;
  237. plotInfo.PlotIndex = i;
  238. CommandList.UpdateBuffer(plotInfoBuffer, 0, plotInfo);
  239. CommandList.Draw(datatotallen);
  240. }
  241. }
  242. }
  243. private uint datastartindex = 0;
  244. private uint datatotallen = 0;
  245. private uint dataLenght = 1000;
  246. public float Interval { get => plotInfo.Interval; set => plotInfo.Interval = value; }
  247. public uint DataLenght
  248. {
  249. get => dataLenght;
  250. set
  251. {
  252. if (dataLenght != value)
  253. {
  254. dataLenght = value;
  255. CreateDataBuffer();
  256. }
  257. }
  258. }
  259. public SeriesInfo[] PlotInfos = new SeriesInfo[0];
  260. }
  261. public class SeriesInfo
  262. {
  263. public RgbaFloat Color;
  264. public bool Visibily;
  265. public string Name = string.Empty;
  266. }
  267. }