PipelineBase.cs 64 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813
  1. using Ryujinx.Common.Memory;
  2. using Ryujinx.Graphics.GAL;
  3. using Ryujinx.Graphics.Shader;
  4. using Silk.NET.Vulkan;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.Linq;
  8. using System.Numerics;
  9. using System.Runtime.CompilerServices;
  10. using System.Runtime.InteropServices;
  11. using BlendOp = Silk.NET.Vulkan.BlendOp;
  12. using Buffer = Silk.NET.Vulkan.Buffer;
  13. using CompareOp = Ryujinx.Graphics.GAL.CompareOp;
  14. using Format = Ryujinx.Graphics.GAL.Format;
  15. using FrontFace = Ryujinx.Graphics.GAL.FrontFace;
  16. using IndexType = Ryujinx.Graphics.GAL.IndexType;
  17. using PolygonMode = Ryujinx.Graphics.GAL.PolygonMode;
  18. using PrimitiveTopology = Ryujinx.Graphics.GAL.PrimitiveTopology;
  19. using Viewport = Ryujinx.Graphics.GAL.Viewport;
  20. namespace Ryujinx.Graphics.Vulkan
  21. {
  22. class PipelineBase : IDisposable
  23. {
  24. public const int DescriptorSetLayouts = 4;
  25. public const int UniformSetIndex = 0;
  26. public const int StorageSetIndex = 1;
  27. public const int TextureSetIndex = 2;
  28. public const int ImageSetIndex = 3;
  29. protected readonly VulkanRenderer Gd;
  30. protected readonly Device Device;
  31. public readonly PipelineCache PipelineCache;
  32. public readonly AutoFlushCounter AutoFlush;
  33. public readonly Action EndRenderPassDelegate;
  34. protected PipelineDynamicState DynamicState;
  35. protected bool IsMainPipeline;
  36. private PipelineState _newState;
  37. private bool _graphicsStateDirty;
  38. private bool _computeStateDirty;
  39. private bool _bindingBarriersDirty;
  40. private PrimitiveTopology _topology;
  41. private ulong _currentPipelineHandle;
  42. protected Auto<DisposablePipeline> Pipeline;
  43. protected PipelineBindPoint Pbp;
  44. protected CommandBufferScoped Cbs;
  45. protected CommandBufferScoped? PreloadCbs;
  46. protected CommandBuffer CommandBuffer;
  47. public CommandBufferScoped CurrentCommandBuffer => Cbs;
  48. private ShaderCollection _program;
  49. protected FramebufferParams FramebufferParams;
  50. private Auto<DisposableFramebuffer> _framebuffer;
  51. private RenderPassHolder _rpHolder;
  52. private Auto<DisposableRenderPass> _renderPass;
  53. private RenderPassHolder _nullRenderPass;
  54. private int _writtenAttachmentCount;
  55. private bool _framebufferUsingColorWriteMask;
  56. private ITexture[] _preMaskColors;
  57. private ITexture _preMaskDepthStencil;
  58. private readonly DescriptorSetUpdater _descriptorSetUpdater;
  59. private IndexBufferState _indexBuffer;
  60. private IndexBufferPattern _indexBufferPattern;
  61. private readonly BufferState[] _transformFeedbackBuffers;
  62. private readonly VertexBufferState[] _vertexBuffers;
  63. private ulong _vertexBuffersDirty;
  64. protected Rectangle<int> ClearScissor;
  65. private readonly VertexBufferUpdater _vertexBufferUpdater;
  66. public IndexBufferPattern QuadsToTrisPattern;
  67. public IndexBufferPattern TriFanToTrisPattern;
  68. private bool _needsIndexBufferRebind;
  69. private bool _needsTransformFeedbackBuffersRebind;
  70. private bool _tfEnabled;
  71. private bool _tfActive;
  72. private FeedbackLoopAspects _feedbackLoop;
  73. private bool _passWritesDepthStencil;
  74. private readonly PipelineColorBlendAttachmentState[] _storedBlend;
  75. public ulong DrawCount { get; private set; }
  76. public bool RenderPassActive { get; private set; }
  77. public unsafe PipelineBase(VulkanRenderer gd, Device device)
  78. {
  79. Gd = gd;
  80. Device = device;
  81. AutoFlush = new AutoFlushCounter(gd);
  82. EndRenderPassDelegate = EndRenderPass;
  83. PipelineCacheCreateInfo pipelineCacheCreateInfo = new PipelineCacheCreateInfo
  84. {
  85. SType = StructureType.PipelineCacheCreateInfo,
  86. };
  87. gd.Api.CreatePipelineCache(device, in pipelineCacheCreateInfo, null, out PipelineCache).ThrowOnError();
  88. _descriptorSetUpdater = new DescriptorSetUpdater(gd, device);
  89. _vertexBufferUpdater = new VertexBufferUpdater(gd);
  90. _transformFeedbackBuffers = new BufferState[Constants.MaxTransformFeedbackBuffers];
  91. _vertexBuffers = new VertexBufferState[Constants.MaxVertexBuffers + 1];
  92. const int EmptyVbSize = 16;
  93. using BufferHolder emptyVb = gd.BufferManager.Create(gd, EmptyVbSize);
  94. emptyVb.SetData(0, new byte[EmptyVbSize]);
  95. _vertexBuffers[0] = new VertexBufferState(emptyVb.GetBuffer(), 0, 0, EmptyVbSize);
  96. _vertexBuffersDirty = ulong.MaxValue >> (64 - _vertexBuffers.Length);
  97. ClearScissor = new Rectangle<int>(0, 0, 0xffff, 0xffff);
  98. _storedBlend = new PipelineColorBlendAttachmentState[Constants.MaxRenderTargets];
  99. _newState.Initialize();
  100. }
  101. public void Initialize()
  102. {
  103. _descriptorSetUpdater.Initialize(IsMainPipeline);
  104. QuadsToTrisPattern = new IndexBufferPattern(Gd, 4, 6, 0, new[] { 0, 1, 2, 0, 2, 3 }, 4, false);
  105. TriFanToTrisPattern = new IndexBufferPattern(Gd, 3, 3, 2, new[] { int.MinValue, -1, 0 }, 1, true);
  106. }
  107. public unsafe void Barrier()
  108. {
  109. Gd.Barriers.QueueMemoryBarrier();
  110. }
  111. public void ComputeBarrier()
  112. {
  113. MemoryBarrier memoryBarrier = new()
  114. {
  115. SType = StructureType.MemoryBarrier,
  116. SrcAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit,
  117. DstAccessMask = AccessFlags.MemoryReadBit | AccessFlags.MemoryWriteBit,
  118. };
  119. Gd.Api.CmdPipelineBarrier(
  120. CommandBuffer,
  121. PipelineStageFlags.ComputeShaderBit,
  122. PipelineStageFlags.AllCommandsBit,
  123. 0,
  124. 1,
  125. new ReadOnlySpan<MemoryBarrier>(in memoryBarrier),
  126. 0,
  127. ReadOnlySpan<BufferMemoryBarrier>.Empty,
  128. 0,
  129. ReadOnlySpan<ImageMemoryBarrier>.Empty);
  130. }
  131. public void BeginTransformFeedback(PrimitiveTopology topology)
  132. {
  133. Gd.Barriers.EnableTfbBarriers(true);
  134. _tfEnabled = true;
  135. }
  136. public void ClearBuffer(BufferHandle destination, int offset, int size, uint value)
  137. {
  138. EndRenderPass();
  139. Buffer dst = Gd.BufferManager.GetBuffer(CommandBuffer, destination, offset, size, true).Get(Cbs, offset, size, true).Value;
  140. BufferHolder.InsertBufferBarrier(
  141. Gd,
  142. Cbs.CommandBuffer,
  143. dst,
  144. BufferHolder.DefaultAccessFlags,
  145. AccessFlags.TransferWriteBit,
  146. PipelineStageFlags.AllCommandsBit,
  147. PipelineStageFlags.TransferBit,
  148. offset,
  149. size);
  150. Gd.Api.CmdFillBuffer(CommandBuffer, dst, (ulong)offset, (ulong)size, value);
  151. BufferHolder.InsertBufferBarrier(
  152. Gd,
  153. Cbs.CommandBuffer,
  154. dst,
  155. AccessFlags.TransferWriteBit,
  156. BufferHolder.DefaultAccessFlags,
  157. PipelineStageFlags.TransferBit,
  158. PipelineStageFlags.AllCommandsBit,
  159. offset,
  160. size);
  161. }
  162. public unsafe void ClearRenderTargetColor(int index, int layer, int layerCount, ColorF color)
  163. {
  164. if (FramebufferParams == null || !FramebufferParams.IsValidColorAttachment(index))
  165. {
  166. return;
  167. }
  168. if (_renderPass == null)
  169. {
  170. CreateRenderPass();
  171. }
  172. Gd.Barriers.Flush(Cbs, RenderPassActive, _rpHolder, EndRenderPassDelegate);
  173. BeginRenderPass();
  174. ClearValue clearValue = new ClearValue(new ClearColorValue(color.Red, color.Green, color.Blue, color.Alpha));
  175. ClearAttachment attachment = new ClearAttachment(ImageAspectFlags.ColorBit, (uint)index, clearValue);
  176. ClearRect clearRect = FramebufferParams.GetClearRect(ClearScissor, layer, layerCount);
  177. Gd.Api.CmdClearAttachments(CommandBuffer, 1, &attachment, 1, &clearRect);
  178. }
  179. public unsafe void ClearRenderTargetDepthStencil(int layer, int layerCount, float depthValue, bool depthMask, int stencilValue, bool stencilMask)
  180. {
  181. if (FramebufferParams == null || !FramebufferParams.HasDepthStencil)
  182. {
  183. return;
  184. }
  185. ClearValue clearValue = new ClearValue(null, new ClearDepthStencilValue(depthValue, (uint)stencilValue));
  186. ImageAspectFlags flags = depthMask ? ImageAspectFlags.DepthBit : 0;
  187. if (stencilMask)
  188. {
  189. flags |= ImageAspectFlags.StencilBit;
  190. }
  191. flags &= FramebufferParams.GetDepthStencilAspectFlags();
  192. if (flags == ImageAspectFlags.None)
  193. {
  194. return;
  195. }
  196. if (_renderPass == null)
  197. {
  198. CreateRenderPass();
  199. }
  200. Gd.Barriers.Flush(Cbs, RenderPassActive, _rpHolder, EndRenderPassDelegate);
  201. BeginRenderPass();
  202. ClearAttachment attachment = new ClearAttachment(flags, 0, clearValue);
  203. ClearRect clearRect = FramebufferParams.GetClearRect(ClearScissor, layer, layerCount);
  204. Gd.Api.CmdClearAttachments(CommandBuffer, 1, &attachment, 1, &clearRect);
  205. }
  206. public unsafe void CommandBufferBarrier()
  207. {
  208. Gd.Barriers.QueueCommandBufferBarrier();
  209. }
  210. public void CopyBuffer(BufferHandle source, BufferHandle destination, int srcOffset, int dstOffset, int size)
  211. {
  212. EndRenderPass();
  213. Auto<DisposableBuffer> src = Gd.BufferManager.GetBuffer(CommandBuffer, source, srcOffset, size, false);
  214. Auto<DisposableBuffer> dst = Gd.BufferManager.GetBuffer(CommandBuffer, destination, dstOffset, size, true);
  215. BufferHolder.Copy(Gd, Cbs, src, dst, srcOffset, dstOffset, size);
  216. }
  217. public void DirtyVertexBuffer(Auto<DisposableBuffer> buffer)
  218. {
  219. for (int i = 0; i < _vertexBuffers.Length; i++)
  220. {
  221. if (_vertexBuffers[i].BoundEquals(buffer))
  222. {
  223. _vertexBuffersDirty |= 1UL << i;
  224. }
  225. }
  226. }
  227. public void DirtyIndexBuffer(Auto<DisposableBuffer> buffer)
  228. {
  229. if (_indexBuffer.BoundEquals(buffer))
  230. {
  231. _needsIndexBufferRebind = true;
  232. }
  233. }
  234. public void DispatchCompute(int groupsX, int groupsY, int groupsZ)
  235. {
  236. if (!_program.IsLinked)
  237. {
  238. return;
  239. }
  240. EndRenderPass();
  241. RecreateComputePipelineIfNeeded();
  242. Gd.Api.CmdDispatch(CommandBuffer, (uint)groupsX, (uint)groupsY, (uint)groupsZ);
  243. }
  244. public void DispatchComputeIndirect(Auto<DisposableBuffer> indirectBuffer, int indirectBufferOffset)
  245. {
  246. if (!_program.IsLinked)
  247. {
  248. return;
  249. }
  250. EndRenderPass();
  251. RecreateComputePipelineIfNeeded();
  252. Gd.Api.CmdDispatchIndirect(CommandBuffer, indirectBuffer.Get(Cbs, indirectBufferOffset, 12).Value, (ulong)indirectBufferOffset);
  253. }
  254. public void Draw(int vertexCount, int instanceCount, int firstVertex, int firstInstance)
  255. {
  256. if (vertexCount == 0)
  257. {
  258. return;
  259. }
  260. if (!RecreateGraphicsPipelineIfNeeded())
  261. {
  262. return;
  263. }
  264. BeginRenderPass();
  265. DrawCount++;
  266. if (Gd.TopologyUnsupported(_topology))
  267. {
  268. // Temporarily bind a conversion pattern as an index buffer.
  269. _needsIndexBufferRebind = true;
  270. IndexBufferPattern pattern = _topology switch
  271. {
  272. PrimitiveTopology.Quads => QuadsToTrisPattern,
  273. PrimitiveTopology.TriangleFan or
  274. PrimitiveTopology.Polygon => TriFanToTrisPattern,
  275. _ => throw new NotSupportedException($"Unsupported topology: {_topology}"),
  276. };
  277. BufferHandle handle = pattern.GetRepeatingBuffer(vertexCount, out int indexCount);
  278. Auto<DisposableBuffer> buffer = Gd.BufferManager.GetBuffer(CommandBuffer, handle, false);
  279. Gd.Api.CmdBindIndexBuffer(CommandBuffer, buffer.Get(Cbs, 0, indexCount * sizeof(int)).Value, 0, Silk.NET.Vulkan.IndexType.Uint32);
  280. BeginRenderPass(); // May have been interrupted to set buffer data.
  281. ResumeTransformFeedbackInternal();
  282. Gd.Api.CmdDrawIndexed(CommandBuffer, (uint)indexCount, (uint)instanceCount, 0, firstVertex, (uint)firstInstance);
  283. }
  284. else
  285. {
  286. ResumeTransformFeedbackInternal();
  287. Gd.Api.CmdDraw(CommandBuffer, (uint)vertexCount, (uint)instanceCount, (uint)firstVertex, (uint)firstInstance);
  288. }
  289. }
  290. private void UpdateIndexBufferPattern()
  291. {
  292. IndexBufferPattern pattern = null;
  293. if (Gd.TopologyUnsupported(_topology))
  294. {
  295. pattern = _topology switch
  296. {
  297. PrimitiveTopology.Quads => QuadsToTrisPattern,
  298. PrimitiveTopology.TriangleFan or
  299. PrimitiveTopology.Polygon => TriFanToTrisPattern,
  300. _ => throw new NotSupportedException($"Unsupported topology: {_topology}"),
  301. };
  302. }
  303. if (_indexBufferPattern != pattern)
  304. {
  305. _indexBufferPattern = pattern;
  306. _needsIndexBufferRebind = true;
  307. }
  308. }
  309. public void DrawIndexed(int indexCount, int instanceCount, int firstIndex, int firstVertex, int firstInstance)
  310. {
  311. if (indexCount == 0)
  312. {
  313. return;
  314. }
  315. UpdateIndexBufferPattern();
  316. if (!RecreateGraphicsPipelineIfNeeded())
  317. {
  318. return;
  319. }
  320. BeginRenderPass();
  321. DrawCount++;
  322. if (_indexBufferPattern != null)
  323. {
  324. // Convert the index buffer into a supported topology.
  325. IndexBufferPattern pattern = _indexBufferPattern;
  326. int convertedCount = pattern.GetConvertedCount(indexCount);
  327. if (_needsIndexBufferRebind)
  328. {
  329. _indexBuffer.BindConvertedIndexBuffer(Gd, Cbs, firstIndex, indexCount, convertedCount, pattern);
  330. _needsIndexBufferRebind = false;
  331. }
  332. BeginRenderPass(); // May have been interrupted to set buffer data.
  333. ResumeTransformFeedbackInternal();
  334. Gd.Api.CmdDrawIndexed(CommandBuffer, (uint)convertedCount, (uint)instanceCount, 0, firstVertex, (uint)firstInstance);
  335. }
  336. else
  337. {
  338. ResumeTransformFeedbackInternal();
  339. Gd.Api.CmdDrawIndexed(CommandBuffer, (uint)indexCount, (uint)instanceCount, (uint)firstIndex, firstVertex, (uint)firstInstance);
  340. }
  341. }
  342. public void DrawIndexedIndirect(BufferRange indirectBuffer)
  343. {
  344. Buffer buffer = Gd.BufferManager
  345. .GetBuffer(CommandBuffer, indirectBuffer.Handle, indirectBuffer.Offset, indirectBuffer.Size, false)
  346. .Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size).Value;
  347. UpdateIndexBufferPattern();
  348. if (!RecreateGraphicsPipelineIfNeeded())
  349. {
  350. return;
  351. }
  352. BeginRenderPass();
  353. DrawCount++;
  354. if (_indexBufferPattern != null)
  355. {
  356. // Convert the index buffer into a supported topology.
  357. IndexBufferPattern pattern = _indexBufferPattern;
  358. Auto<DisposableBuffer> indirectBufferAuto = _indexBuffer.BindConvertedIndexBufferIndirect(
  359. Gd,
  360. Cbs,
  361. indirectBuffer,
  362. BufferRange.Empty,
  363. pattern,
  364. false,
  365. 1,
  366. indirectBuffer.Size);
  367. _needsIndexBufferRebind = false;
  368. BeginRenderPass(); // May have been interrupted to set buffer data.
  369. ResumeTransformFeedbackInternal();
  370. Gd.Api.CmdDrawIndexedIndirect(CommandBuffer, indirectBufferAuto.Get(Cbs, 0, indirectBuffer.Size).Value, 0, 1, (uint)indirectBuffer.Size);
  371. }
  372. else
  373. {
  374. ResumeTransformFeedbackInternal();
  375. Gd.Api.CmdDrawIndexedIndirect(CommandBuffer, buffer, (ulong)indirectBuffer.Offset, 1, (uint)indirectBuffer.Size);
  376. }
  377. }
  378. public void DrawIndexedIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
  379. {
  380. Buffer countBuffer = Gd.BufferManager
  381. .GetBuffer(CommandBuffer, parameterBuffer.Handle, parameterBuffer.Offset, parameterBuffer.Size, false)
  382. .Get(Cbs, parameterBuffer.Offset, parameterBuffer.Size).Value;
  383. Buffer buffer = Gd.BufferManager
  384. .GetBuffer(CommandBuffer, indirectBuffer.Handle, indirectBuffer.Offset, indirectBuffer.Size, false)
  385. .Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size).Value;
  386. UpdateIndexBufferPattern();
  387. if (!RecreateGraphicsPipelineIfNeeded())
  388. {
  389. return;
  390. }
  391. BeginRenderPass();
  392. DrawCount++;
  393. if (_indexBufferPattern != null)
  394. {
  395. // Convert the index buffer into a supported topology.
  396. IndexBufferPattern pattern = _indexBufferPattern;
  397. Auto<DisposableBuffer> indirectBufferAuto = _indexBuffer.BindConvertedIndexBufferIndirect(
  398. Gd,
  399. Cbs,
  400. indirectBuffer,
  401. parameterBuffer,
  402. pattern,
  403. true,
  404. maxDrawCount,
  405. stride);
  406. _needsIndexBufferRebind = false;
  407. BeginRenderPass(); // May have been interrupted to set buffer data.
  408. ResumeTransformFeedbackInternal();
  409. if (Gd.Capabilities.SupportsIndirectParameters)
  410. {
  411. Gd.DrawIndirectCountApi.CmdDrawIndexedIndirectCount(
  412. CommandBuffer,
  413. indirectBufferAuto.Get(Cbs, 0, indirectBuffer.Size).Value,
  414. 0,
  415. countBuffer,
  416. (ulong)parameterBuffer.Offset,
  417. (uint)maxDrawCount,
  418. (uint)stride);
  419. }
  420. else
  421. {
  422. // This is also fine because the indirect data conversion always zeros
  423. // the entries that are past the current draw count.
  424. Gd.Api.CmdDrawIndexedIndirect(
  425. CommandBuffer,
  426. indirectBufferAuto.Get(Cbs, 0, indirectBuffer.Size).Value,
  427. 0,
  428. (uint)maxDrawCount,
  429. (uint)stride);
  430. }
  431. }
  432. else
  433. {
  434. ResumeTransformFeedbackInternal();
  435. if (Gd.Capabilities.SupportsIndirectParameters)
  436. {
  437. Gd.DrawIndirectCountApi.CmdDrawIndexedIndirectCount(
  438. CommandBuffer,
  439. buffer,
  440. (ulong)indirectBuffer.Offset,
  441. countBuffer,
  442. (ulong)parameterBuffer.Offset,
  443. (uint)maxDrawCount,
  444. (uint)stride);
  445. }
  446. else
  447. {
  448. // Not fully correct, but we can't do much better if the host does not support indirect count.
  449. Gd.Api.CmdDrawIndexedIndirect(
  450. CommandBuffer,
  451. buffer,
  452. (ulong)indirectBuffer.Offset,
  453. (uint)maxDrawCount,
  454. (uint)stride);
  455. }
  456. }
  457. }
  458. public void DrawIndirect(BufferRange indirectBuffer)
  459. {
  460. // TODO: Support quads and other unsupported topologies.
  461. Buffer buffer = Gd.BufferManager
  462. .GetBuffer(CommandBuffer, indirectBuffer.Handle, indirectBuffer.Offset, indirectBuffer.Size, false)
  463. .Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size, false).Value;
  464. if (!RecreateGraphicsPipelineIfNeeded())
  465. {
  466. return;
  467. }
  468. BeginRenderPass();
  469. ResumeTransformFeedbackInternal();
  470. DrawCount++;
  471. Gd.Api.CmdDrawIndirect(CommandBuffer, buffer, (ulong)indirectBuffer.Offset, 1, (uint)indirectBuffer.Size);
  472. }
  473. public void DrawIndirectCount(BufferRange indirectBuffer, BufferRange parameterBuffer, int maxDrawCount, int stride)
  474. {
  475. if (!Gd.Capabilities.SupportsIndirectParameters)
  476. {
  477. // TODO: Fallback for when this is not supported.
  478. throw new NotSupportedException();
  479. }
  480. Buffer buffer = Gd.BufferManager
  481. .GetBuffer(CommandBuffer, indirectBuffer.Handle, indirectBuffer.Offset, indirectBuffer.Size, false)
  482. .Get(Cbs, indirectBuffer.Offset, indirectBuffer.Size, false).Value;
  483. Buffer countBuffer = Gd.BufferManager
  484. .GetBuffer(CommandBuffer, parameterBuffer.Handle, parameterBuffer.Offset, parameterBuffer.Size, false)
  485. .Get(Cbs, parameterBuffer.Offset, parameterBuffer.Size, false).Value;
  486. // TODO: Support quads and other unsupported topologies.
  487. if (!RecreateGraphicsPipelineIfNeeded())
  488. {
  489. return;
  490. }
  491. BeginRenderPass();
  492. ResumeTransformFeedbackInternal();
  493. DrawCount++;
  494. Gd.DrawIndirectCountApi.CmdDrawIndirectCount(
  495. CommandBuffer,
  496. buffer,
  497. (ulong)indirectBuffer.Offset,
  498. countBuffer,
  499. (ulong)parameterBuffer.Offset,
  500. (uint)maxDrawCount,
  501. (uint)stride);
  502. }
  503. public void DrawTexture(ITexture texture, ISampler sampler, Extents2DF srcRegion, Extents2DF dstRegion)
  504. {
  505. if (texture is TextureView srcTexture)
  506. {
  507. CullModeFlags oldCullMode = _newState.CullMode;
  508. bool oldStencilTestEnable = _newState.StencilTestEnable;
  509. bool oldDepthTestEnable = _newState.DepthTestEnable;
  510. bool oldDepthWriteEnable = _newState.DepthWriteEnable;
  511. Array16<Silk.NET.Vulkan.Viewport> oldViewports = DynamicState.Viewports;
  512. uint oldViewportsCount = _newState.ViewportsCount;
  513. PrimitiveTopology oldTopology = _topology;
  514. _newState.CullMode = CullModeFlags.None;
  515. _newState.StencilTestEnable = false;
  516. _newState.DepthTestEnable = false;
  517. _newState.DepthWriteEnable = false;
  518. SignalStateChange();
  519. Gd.HelperShader.DrawTexture(
  520. Gd,
  521. this,
  522. srcTexture,
  523. sampler,
  524. srcRegion,
  525. dstRegion);
  526. _newState.CullMode = oldCullMode;
  527. _newState.StencilTestEnable = oldStencilTestEnable;
  528. _newState.DepthTestEnable = oldDepthTestEnable;
  529. _newState.DepthWriteEnable = oldDepthWriteEnable;
  530. SetPrimitiveTopology(oldTopology);
  531. DynamicState.SetViewports(ref oldViewports, oldViewportsCount);
  532. _newState.ViewportsCount = oldViewportsCount;
  533. SignalStateChange();
  534. }
  535. }
  536. public void EndTransformFeedback()
  537. {
  538. Gd.Barriers.EnableTfbBarriers(false);
  539. PauseTransformFeedbackInternal();
  540. _tfEnabled = false;
  541. }
  542. public bool IsCommandBufferActive(CommandBuffer cb)
  543. {
  544. return CommandBuffer.Handle == cb.Handle;
  545. }
  546. internal void Rebind(Auto<DisposableBuffer> buffer, int offset, int size)
  547. {
  548. _descriptorSetUpdater.Rebind(buffer, offset, size);
  549. if (_indexBuffer.Overlaps(buffer, offset, size))
  550. {
  551. _indexBuffer.BindIndexBuffer(Gd, Cbs);
  552. }
  553. for (int i = 0; i < _vertexBuffers.Length; i++)
  554. {
  555. if (_vertexBuffers[i].Overlaps(buffer, offset, size))
  556. {
  557. _vertexBuffers[i].BindVertexBuffer(Gd, Cbs, (uint)i, ref _newState, _vertexBufferUpdater);
  558. }
  559. }
  560. _vertexBufferUpdater.Commit(Cbs);
  561. }
  562. public void SetAlphaTest(bool enable, float reference, CompareOp op)
  563. {
  564. // This is currently handled using shader specialization, as Vulkan does not support alpha test.
  565. // In the future, we may want to use this to write the reference value into the support buffer,
  566. // to avoid creating one version of the shader per reference value used.
  567. }
  568. public void SetBlendState(AdvancedBlendDescriptor blend)
  569. {
  570. for (int index = 0; index < Constants.MaxRenderTargets; index++)
  571. {
  572. ref PipelineColorBlendAttachmentState vkBlend = ref _newState.Internal.ColorBlendAttachmentState[index];
  573. if (index == 0)
  574. {
  575. BlendOp blendOp = blend.Op.Convert();
  576. vkBlend = new PipelineColorBlendAttachmentState(
  577. blendEnable: true,
  578. colorBlendOp: blendOp,
  579. alphaBlendOp: blendOp,
  580. colorWriteMask: vkBlend.ColorWriteMask);
  581. if (Gd.Capabilities.SupportsBlendEquationAdvancedNonPreMultipliedSrcColor)
  582. {
  583. _newState.AdvancedBlendSrcPreMultiplied = blend.SrcPreMultiplied;
  584. }
  585. if (Gd.Capabilities.SupportsBlendEquationAdvancedCorrelatedOverlap)
  586. {
  587. _newState.AdvancedBlendOverlap = blend.Overlap.Convert();
  588. }
  589. }
  590. else
  591. {
  592. vkBlend = new PipelineColorBlendAttachmentState(
  593. colorWriteMask: vkBlend.ColorWriteMask);
  594. }
  595. if (vkBlend.ColorWriteMask == 0)
  596. {
  597. _storedBlend[index] = vkBlend;
  598. vkBlend = new PipelineColorBlendAttachmentState();
  599. }
  600. }
  601. SignalStateChange();
  602. }
  603. public void SetBlendState(int index, BlendDescriptor blend)
  604. {
  605. ref PipelineColorBlendAttachmentState vkBlend = ref _newState.Internal.ColorBlendAttachmentState[index];
  606. if (blend.Enable)
  607. {
  608. vkBlend.BlendEnable = blend.Enable;
  609. vkBlend.SrcColorBlendFactor = blend.ColorSrcFactor.Convert();
  610. vkBlend.DstColorBlendFactor = blend.ColorDstFactor.Convert();
  611. vkBlend.ColorBlendOp = blend.ColorOp.Convert();
  612. vkBlend.SrcAlphaBlendFactor = blend.AlphaSrcFactor.Convert();
  613. vkBlend.DstAlphaBlendFactor = blend.AlphaDstFactor.Convert();
  614. vkBlend.AlphaBlendOp = blend.AlphaOp.Convert();
  615. }
  616. else
  617. {
  618. vkBlend = new PipelineColorBlendAttachmentState(
  619. colorWriteMask: vkBlend.ColorWriteMask);
  620. }
  621. if (vkBlend.ColorWriteMask == 0)
  622. {
  623. _storedBlend[index] = vkBlend;
  624. vkBlend = new PipelineColorBlendAttachmentState();
  625. }
  626. DynamicState.SetBlendConstants(
  627. blend.BlendConstant.Red,
  628. blend.BlendConstant.Green,
  629. blend.BlendConstant.Blue,
  630. blend.BlendConstant.Alpha);
  631. // Reset advanced blend state back defaults to the cache to help the pipeline cache.
  632. _newState.AdvancedBlendSrcPreMultiplied = true;
  633. _newState.AdvancedBlendDstPreMultiplied = true;
  634. _newState.AdvancedBlendOverlap = BlendOverlapEXT.UncorrelatedExt;
  635. SignalStateChange();
  636. }
  637. public void SetDepthBias(PolygonModeMask enables, float factor, float units, float clamp)
  638. {
  639. DynamicState.SetDepthBias(factor, units, clamp);
  640. _newState.DepthBiasEnable = enables != 0;
  641. SignalStateChange();
  642. }
  643. public void SetDepthClamp(bool clamp)
  644. {
  645. _newState.DepthClampEnable = clamp;
  646. SignalStateChange();
  647. }
  648. public void SetDepthMode(DepthMode mode)
  649. {
  650. bool oldMode = _newState.DepthMode;
  651. _newState.DepthMode = mode == DepthMode.MinusOneToOne;
  652. if (_newState.DepthMode != oldMode)
  653. {
  654. SignalStateChange();
  655. }
  656. }
  657. public void SetDepthTest(DepthTestDescriptor depthTest)
  658. {
  659. _newState.DepthTestEnable = depthTest.TestEnable;
  660. _newState.DepthWriteEnable = depthTest.WriteEnable;
  661. _newState.DepthCompareOp = depthTest.Func.Convert();
  662. UpdatePassDepthStencil();
  663. SignalStateChange();
  664. }
  665. public void SetFaceCulling(bool enable, Face face)
  666. {
  667. _newState.CullMode = enable ? face.Convert() : CullModeFlags.None;
  668. SignalStateChange();
  669. }
  670. public void SetFrontFace(FrontFace frontFace)
  671. {
  672. _newState.FrontFace = frontFace.Convert();
  673. SignalStateChange();
  674. }
  675. public void SetImage(ShaderStage stage, int binding, ITexture image)
  676. {
  677. _descriptorSetUpdater.SetImage(Cbs, stage, binding, image);
  678. }
  679. public void SetImage(int binding, Auto<DisposableImageView> image)
  680. {
  681. _descriptorSetUpdater.SetImage(binding, image);
  682. }
  683. public void SetImageArray(ShaderStage stage, int binding, IImageArray array)
  684. {
  685. _descriptorSetUpdater.SetImageArray(Cbs, stage, binding, array);
  686. }
  687. public void SetImageArraySeparate(ShaderStage stage, int setIndex, IImageArray array)
  688. {
  689. _descriptorSetUpdater.SetImageArraySeparate(Cbs, stage, setIndex, array);
  690. }
  691. public void SetIndexBuffer(BufferRange buffer, IndexType type)
  692. {
  693. if (buffer.Handle != BufferHandle.Null)
  694. {
  695. _indexBuffer = new IndexBufferState(buffer.Handle, buffer.Offset, buffer.Size, type.Convert());
  696. }
  697. else
  698. {
  699. _indexBuffer = IndexBufferState.Null;
  700. }
  701. _needsIndexBufferRebind = true;
  702. }
  703. public void SetLineParameters(float width, bool smooth)
  704. {
  705. _newState.LineWidth = width;
  706. SignalStateChange();
  707. }
  708. public void SetLogicOpState(bool enable, LogicalOp op)
  709. {
  710. _newState.LogicOpEnable = enable;
  711. _newState.LogicOp = op.Convert();
  712. SignalStateChange();
  713. }
  714. public void SetMultisampleState(MultisampleDescriptor multisample)
  715. {
  716. _newState.AlphaToCoverageEnable = multisample.AlphaToCoverageEnable;
  717. _newState.AlphaToOneEnable = multisample.AlphaToOneEnable;
  718. SignalStateChange();
  719. }
  720. public void SetPatchParameters(int vertices, ReadOnlySpan<float> defaultOuterLevel, ReadOnlySpan<float> defaultInnerLevel)
  721. {
  722. _newState.PatchControlPoints = (uint)vertices;
  723. SignalStateChange();
  724. // TODO: Default levels (likely needs emulation on shaders?)
  725. }
  726. public void SetPointParameters(float size, bool isProgramPointSize, bool enablePointSprite, Origin origin)
  727. {
  728. // TODO.
  729. }
  730. public void SetPolygonMode(PolygonMode frontMode, PolygonMode backMode)
  731. {
  732. // TODO.
  733. }
  734. public void SetPrimitiveRestart(bool enable, int index)
  735. {
  736. _newState.PrimitiveRestartEnable = enable;
  737. // TODO: What to do about the index?
  738. SignalStateChange();
  739. }
  740. public void SetPrimitiveTopology(PrimitiveTopology topology)
  741. {
  742. _topology = topology;
  743. Silk.NET.Vulkan.PrimitiveTopology vkTopology = Gd.TopologyRemap(topology).Convert();
  744. _newState.Topology = vkTopology;
  745. SignalStateChange();
  746. }
  747. public void SetProgram(IProgram program)
  748. {
  749. ShaderCollection internalProgram = (ShaderCollection)program;
  750. PipelineShaderStageCreateInfo[] stages = internalProgram.GetInfos();
  751. _program = internalProgram;
  752. _descriptorSetUpdater.SetProgram(Cbs, internalProgram, _currentPipelineHandle != 0);
  753. _bindingBarriersDirty = true;
  754. _newState.PipelineLayout = internalProgram.PipelineLayout;
  755. _newState.HasTessellationControlShader = internalProgram.HasTessellationControlShader;
  756. _newState.StagesCount = (uint)stages.Length;
  757. stages.CopyTo(_newState.Stages.AsSpan()[..stages.Length]);
  758. SignalStateChange();
  759. if (internalProgram.IsCompute)
  760. {
  761. EndRenderPass();
  762. }
  763. }
  764. public void Specialize<T>(in T data) where T : unmanaged
  765. {
  766. ReadOnlySpan<byte> dataSpan = MemoryMarshal.AsBytes(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.AsRef(in data), 1));
  767. if (!dataSpan.SequenceEqual(_newState.SpecializationData.Span))
  768. {
  769. _newState.SpecializationData = new SpecData(dataSpan);
  770. SignalStateChange();
  771. }
  772. }
  773. protected virtual void SignalAttachmentChange()
  774. {
  775. }
  776. public void SetRasterizerDiscard(bool discard)
  777. {
  778. _newState.RasterizerDiscardEnable = discard;
  779. SignalStateChange();
  780. if (!discard && Gd.IsQualcommProprietary)
  781. {
  782. // On Adreno, enabling rasterizer discard somehow corrupts the viewport state.
  783. // Force it to be updated on next use to work around this bug.
  784. DynamicState.ForceAllDirty();
  785. }
  786. }
  787. public void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMask)
  788. {
  789. int count = Math.Min(Constants.MaxRenderTargets, componentMask.Length);
  790. int writtenAttachments = 0;
  791. for (int i = 0; i < count; i++)
  792. {
  793. ref PipelineColorBlendAttachmentState vkBlend = ref _newState.Internal.ColorBlendAttachmentState[i];
  794. ColorComponentFlags newMask = (ColorComponentFlags)componentMask[i];
  795. // When color write mask is 0, remove all blend state to help the pipeline cache.
  796. // Restore it when the mask becomes non-zero.
  797. if (vkBlend.ColorWriteMask != newMask)
  798. {
  799. if (newMask == 0)
  800. {
  801. _storedBlend[i] = vkBlend;
  802. vkBlend = new PipelineColorBlendAttachmentState();
  803. }
  804. else if (vkBlend.ColorWriteMask == 0)
  805. {
  806. vkBlend = _storedBlend[i];
  807. }
  808. }
  809. vkBlend.ColorWriteMask = newMask;
  810. if (componentMask[i] != 0)
  811. {
  812. writtenAttachments++;
  813. }
  814. }
  815. if (_framebufferUsingColorWriteMask)
  816. {
  817. SetRenderTargetsInternal(_preMaskColors, _preMaskDepthStencil, true);
  818. }
  819. else
  820. {
  821. SignalStateChange();
  822. if (writtenAttachments != _writtenAttachmentCount)
  823. {
  824. SignalAttachmentChange();
  825. _writtenAttachmentCount = writtenAttachments;
  826. }
  827. }
  828. }
  829. private void SetRenderTargetsInternal(ITexture[] colors, ITexture depthStencil, bool filterWriteMasked)
  830. {
  831. CreateFramebuffer(colors, depthStencil, filterWriteMasked);
  832. CreateRenderPass();
  833. SignalStateChange();
  834. SignalAttachmentChange();
  835. }
  836. public void SetRenderTargets(ITexture[] colors, ITexture depthStencil)
  837. {
  838. _framebufferUsingColorWriteMask = false;
  839. SetRenderTargetsInternal(colors, depthStencil, Gd.IsTBDR);
  840. }
  841. public void SetScissors(ReadOnlySpan<Rectangle<int>> regions)
  842. {
  843. int maxScissors = Gd.Capabilities.SupportsMultiView ? Constants.MaxViewports : 1;
  844. int count = Math.Min(maxScissors, regions.Length);
  845. if (count > 0)
  846. {
  847. ClearScissor = regions[0];
  848. }
  849. for (int i = 0; i < count; i++)
  850. {
  851. Rectangle<int> region = regions[i];
  852. Offset2D offset = new Offset2D(region.X, region.Y);
  853. Extent2D extent = new Extent2D((uint)region.Width, (uint)region.Height);
  854. DynamicState.SetScissor(i, new Rect2D(offset, extent));
  855. }
  856. DynamicState.ScissorsCount = count;
  857. _newState.ScissorsCount = (uint)count;
  858. SignalStateChange();
  859. }
  860. public void SetStencilTest(StencilTestDescriptor stencilTest)
  861. {
  862. DynamicState.SetStencilMasks(
  863. (uint)stencilTest.BackFuncMask,
  864. (uint)stencilTest.BackMask,
  865. (uint)stencilTest.BackFuncRef,
  866. (uint)stencilTest.FrontFuncMask,
  867. (uint)stencilTest.FrontMask,
  868. (uint)stencilTest.FrontFuncRef);
  869. _newState.StencilTestEnable = stencilTest.TestEnable;
  870. _newState.StencilBackFailOp = stencilTest.BackSFail.Convert();
  871. _newState.StencilBackPassOp = stencilTest.BackDpPass.Convert();
  872. _newState.StencilBackDepthFailOp = stencilTest.BackDpFail.Convert();
  873. _newState.StencilBackCompareOp = stencilTest.BackFunc.Convert();
  874. _newState.StencilFrontFailOp = stencilTest.FrontSFail.Convert();
  875. _newState.StencilFrontPassOp = stencilTest.FrontDpPass.Convert();
  876. _newState.StencilFrontDepthFailOp = stencilTest.FrontDpFail.Convert();
  877. _newState.StencilFrontCompareOp = stencilTest.FrontFunc.Convert();
  878. UpdatePassDepthStencil();
  879. SignalStateChange();
  880. }
  881. public void SetStorageBuffers(ReadOnlySpan<BufferAssignment> buffers)
  882. {
  883. _descriptorSetUpdater.SetStorageBuffers(CommandBuffer, buffers);
  884. }
  885. public void SetStorageBuffers(int first, ReadOnlySpan<Auto<DisposableBuffer>> buffers)
  886. {
  887. _descriptorSetUpdater.SetStorageBuffers(CommandBuffer, first, buffers);
  888. }
  889. public void SetTextureAndSampler(ShaderStage stage, int binding, ITexture texture, ISampler sampler)
  890. {
  891. _descriptorSetUpdater.SetTextureAndSampler(Cbs, stage, binding, texture, sampler);
  892. }
  893. public void SetTextureAndSamplerIdentitySwizzle(ShaderStage stage, int binding, ITexture texture, ISampler sampler)
  894. {
  895. _descriptorSetUpdater.SetTextureAndSamplerIdentitySwizzle(Cbs, stage, binding, texture, sampler);
  896. }
  897. public void SetTextureArray(ShaderStage stage, int binding, ITextureArray array)
  898. {
  899. _descriptorSetUpdater.SetTextureArray(Cbs, stage, binding, array);
  900. }
  901. public void SetTextureArraySeparate(ShaderStage stage, int setIndex, ITextureArray array)
  902. {
  903. _descriptorSetUpdater.SetTextureArraySeparate(Cbs, stage, setIndex, array);
  904. }
  905. public void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers)
  906. {
  907. PauseTransformFeedbackInternal();
  908. int count = Math.Min(Constants.MaxTransformFeedbackBuffers, buffers.Length);
  909. for (int i = 0; i < count; i++)
  910. {
  911. BufferRange range = buffers[i];
  912. _transformFeedbackBuffers[i].Dispose();
  913. if (range.Handle != BufferHandle.Null)
  914. {
  915. _transformFeedbackBuffers[i] =
  916. new BufferState(Gd.BufferManager.GetBuffer(CommandBuffer, range.Handle, range.Offset, range.Size, true), range.Offset, range.Size);
  917. _transformFeedbackBuffers[i].BindTransformFeedbackBuffer(Gd, Cbs, (uint)i);
  918. }
  919. else
  920. {
  921. _transformFeedbackBuffers[i] = BufferState.Null;
  922. }
  923. }
  924. }
  925. public void SetUniformBuffers(ReadOnlySpan<BufferAssignment> buffers)
  926. {
  927. _descriptorSetUpdater.SetUniformBuffers(CommandBuffer, buffers);
  928. }
  929. public void SetUserClipDistance(int index, bool enableClip)
  930. {
  931. // TODO.
  932. }
  933. public void SetVertexAttribs(ReadOnlySpan<VertexAttribDescriptor> vertexAttribs)
  934. {
  935. FormatCapabilities formatCapabilities = Gd.FormatCapabilities;
  936. Span<int> newVbScalarSizes = stackalloc int[Constants.MaxVertexBuffers];
  937. int count = Math.Min(Constants.MaxVertexAttributes, vertexAttribs.Length);
  938. uint dirtyVbSizes = 0;
  939. for (int i = 0; i < count; i++)
  940. {
  941. VertexAttribDescriptor attribute = vertexAttribs[i];
  942. int rawIndex = attribute.BufferIndex;
  943. int bufferIndex = attribute.IsZero ? 0 : rawIndex + 1;
  944. if (!attribute.IsZero)
  945. {
  946. newVbScalarSizes[rawIndex] = Math.Max(newVbScalarSizes[rawIndex], attribute.Format.GetScalarSize());
  947. dirtyVbSizes |= 1u << rawIndex;
  948. }
  949. _newState.Internal.VertexAttributeDescriptions[i] = new VertexInputAttributeDescription(
  950. (uint)i,
  951. (uint)bufferIndex,
  952. formatCapabilities.ConvertToVertexVkFormat(attribute.Format),
  953. (uint)attribute.Offset);
  954. }
  955. while (dirtyVbSizes != 0)
  956. {
  957. int dirtyBit = BitOperations.TrailingZeroCount(dirtyVbSizes);
  958. ref VertexBufferState buffer = ref _vertexBuffers[dirtyBit + 1];
  959. if (buffer.AttributeScalarAlignment != newVbScalarSizes[dirtyBit])
  960. {
  961. _vertexBuffersDirty |= 1UL << (dirtyBit + 1);
  962. buffer.AttributeScalarAlignment = newVbScalarSizes[dirtyBit];
  963. }
  964. dirtyVbSizes &= ~(1u << dirtyBit);
  965. }
  966. _newState.VertexAttributeDescriptionsCount = (uint)count;
  967. SignalStateChange();
  968. }
  969. public void SetVertexBuffers(ReadOnlySpan<VertexBufferDescriptor> vertexBuffers)
  970. {
  971. int count = Math.Min(Constants.MaxVertexBuffers, vertexBuffers.Length);
  972. _newState.Internal.VertexBindingDescriptions[0] = new VertexInputBindingDescription(0, 0, VertexInputRate.Vertex);
  973. int validCount = 1;
  974. BufferHandle lastHandle = default;
  975. Auto<DisposableBuffer> lastBuffer = default;
  976. for (int i = 0; i < count; i++)
  977. {
  978. VertexBufferDescriptor vertexBuffer = vertexBuffers[i];
  979. // TODO: Support divisor > 1
  980. VertexInputRate inputRate = vertexBuffer.Divisor != 0 ? VertexInputRate.Instance : VertexInputRate.Vertex;
  981. if (vertexBuffer.Buffer.Handle != BufferHandle.Null)
  982. {
  983. Auto<DisposableBuffer> vb = (vertexBuffer.Buffer.Handle == lastHandle) ? lastBuffer :
  984. Gd.BufferManager.GetBuffer(CommandBuffer, vertexBuffer.Buffer.Handle, false);
  985. lastHandle = vertexBuffer.Buffer.Handle;
  986. lastBuffer = vb;
  987. if (vb != null)
  988. {
  989. int binding = i + 1;
  990. int descriptorIndex = validCount++;
  991. _newState.Internal.VertexBindingDescriptions[descriptorIndex] = new VertexInputBindingDescription(
  992. (uint)binding,
  993. (uint)vertexBuffer.Stride,
  994. inputRate);
  995. int vbSize = vertexBuffer.Buffer.Size;
  996. if (Gd.Vendor == Vendor.Amd && !Gd.IsMoltenVk && vertexBuffer.Stride > 0)
  997. {
  998. // AMD has a bug where if offset + stride * count is greater than
  999. // the size, then the last attribute will have the wrong value.
  1000. // As a workaround, simply use the full buffer size.
  1001. int remainder = vbSize % vertexBuffer.Stride;
  1002. if (remainder != 0)
  1003. {
  1004. vbSize += vertexBuffer.Stride - remainder;
  1005. }
  1006. }
  1007. ref VertexBufferState buffer = ref _vertexBuffers[binding];
  1008. int oldScalarAlign = buffer.AttributeScalarAlignment;
  1009. if (Gd.Capabilities.VertexBufferAlignment < 2 &&
  1010. (vertexBuffer.Stride % FormatExtensions.MaxBufferFormatScalarSize) == 0)
  1011. {
  1012. if (!buffer.Matches(vb, descriptorIndex, vertexBuffer.Buffer.Offset, vbSize, vertexBuffer.Stride))
  1013. {
  1014. buffer.Dispose();
  1015. buffer = new VertexBufferState(
  1016. vb,
  1017. descriptorIndex,
  1018. vertexBuffer.Buffer.Offset,
  1019. vbSize,
  1020. vertexBuffer.Stride);
  1021. buffer.BindVertexBuffer(Gd, Cbs, (uint)binding, ref _newState, _vertexBufferUpdater);
  1022. }
  1023. }
  1024. else
  1025. {
  1026. // May need to be rewritten. Bind this buffer before draw.
  1027. buffer.Dispose();
  1028. buffer = new VertexBufferState(
  1029. vertexBuffer.Buffer.Handle,
  1030. descriptorIndex,
  1031. vertexBuffer.Buffer.Offset,
  1032. vbSize,
  1033. vertexBuffer.Stride);
  1034. _vertexBuffersDirty |= 1UL << binding;
  1035. }
  1036. buffer.AttributeScalarAlignment = oldScalarAlign;
  1037. }
  1038. }
  1039. }
  1040. _vertexBufferUpdater.Commit(Cbs);
  1041. _newState.VertexBindingDescriptionsCount = (uint)validCount;
  1042. SignalStateChange();
  1043. }
  1044. public void SetViewports(ReadOnlySpan<Viewport> viewports)
  1045. {
  1046. int maxViewports = Gd.Capabilities.SupportsMultiView ? Constants.MaxViewports : 1;
  1047. int count = Math.Min(maxViewports, viewports.Length);
  1048. static float Clamp(float value)
  1049. {
  1050. return Math.Clamp(value, 0f, 1f);
  1051. }
  1052. DynamicState.ViewportsCount = (uint)count;
  1053. for (int i = 0; i < count; i++)
  1054. {
  1055. Viewport viewport = viewports[i];
  1056. DynamicState.SetViewport(i, new Silk.NET.Vulkan.Viewport(
  1057. viewport.Region.X,
  1058. viewport.Region.Y,
  1059. viewport.Region.Width == 0f ? 1f : viewport.Region.Width,
  1060. viewport.Region.Height == 0f ? 1f : viewport.Region.Height,
  1061. Clamp(viewport.DepthNear),
  1062. Clamp(viewport.DepthFar)));
  1063. }
  1064. _newState.ViewportsCount = (uint)count;
  1065. SignalStateChange();
  1066. }
  1067. public void SwapBuffer(Auto<DisposableBuffer> from, Auto<DisposableBuffer> to)
  1068. {
  1069. _indexBuffer.Swap(from, to);
  1070. for (int i = 0; i < _vertexBuffers.Length; i++)
  1071. {
  1072. _vertexBuffers[i].Swap(from, to);
  1073. }
  1074. for (int i = 0; i < _transformFeedbackBuffers.Length; i++)
  1075. {
  1076. _transformFeedbackBuffers[i].Swap(from, to);
  1077. }
  1078. _descriptorSetUpdater.SwapBuffer(from, to);
  1079. SignalCommandBufferChange();
  1080. }
  1081. public void ForceTextureDirty()
  1082. {
  1083. _descriptorSetUpdater.ForceTextureDirty();
  1084. }
  1085. public void ForceImageDirty()
  1086. {
  1087. _descriptorSetUpdater.ForceImageDirty();
  1088. }
  1089. public unsafe void TextureBarrier()
  1090. {
  1091. Gd.Barriers.QueueTextureBarrier();
  1092. }
  1093. public void TextureBarrierTiled()
  1094. {
  1095. TextureBarrier();
  1096. }
  1097. protected void SignalCommandBufferChange()
  1098. {
  1099. _needsIndexBufferRebind = true;
  1100. _needsTransformFeedbackBuffersRebind = true;
  1101. _vertexBuffersDirty = ulong.MaxValue >> (64 - _vertexBuffers.Length);
  1102. _descriptorSetUpdater.SignalCommandBufferChange();
  1103. DynamicState.ForceAllDirty();
  1104. _currentPipelineHandle = 0;
  1105. }
  1106. private void CreateFramebuffer(ITexture[] colors, ITexture depthStencil, bool filterWriteMasked)
  1107. {
  1108. if (filterWriteMasked)
  1109. {
  1110. // TBDR GPUs don't work properly if the same attachment is bound to multiple targets,
  1111. // due to each attachment being a copy of the real attachment, rather than a direct write.
  1112. // Just try to remove duplicate attachments.
  1113. // Save a copy of the array to rebind when mask changes.
  1114. void MaskOut()
  1115. {
  1116. if (!_framebufferUsingColorWriteMask)
  1117. {
  1118. _preMaskColors = colors.ToArray();
  1119. _preMaskDepthStencil = depthStencil;
  1120. }
  1121. // If true, then the framebuffer must be recreated when the mask changes.
  1122. _framebufferUsingColorWriteMask = true;
  1123. }
  1124. // Look for textures that are masked out.
  1125. for (int i = 0; i < colors.Length; i++)
  1126. {
  1127. if (colors[i] == null)
  1128. {
  1129. continue;
  1130. }
  1131. ref PipelineColorBlendAttachmentState vkBlend = ref _newState.Internal.ColorBlendAttachmentState[i];
  1132. for (int j = 0; j < i; j++)
  1133. {
  1134. // Check each binding for a duplicate binding before it.
  1135. if (colors[i] == colors[j])
  1136. {
  1137. // Prefer the binding with no write mask.
  1138. ref PipelineColorBlendAttachmentState vkBlend2 = ref _newState.Internal.ColorBlendAttachmentState[j];
  1139. if (vkBlend.ColorWriteMask == 0)
  1140. {
  1141. colors[i] = null;
  1142. MaskOut();
  1143. }
  1144. else if (vkBlend2.ColorWriteMask == 0)
  1145. {
  1146. colors[j] = null;
  1147. MaskOut();
  1148. }
  1149. }
  1150. }
  1151. }
  1152. }
  1153. if (IsMainPipeline)
  1154. {
  1155. FramebufferParams?.ClearBindings();
  1156. }
  1157. FramebufferParams = new FramebufferParams(Device, colors, depthStencil);
  1158. if (IsMainPipeline)
  1159. {
  1160. FramebufferParams.AddBindings();
  1161. _newState.FeedbackLoopAspects = FeedbackLoopAspects.None;
  1162. _bindingBarriersDirty = true;
  1163. }
  1164. _passWritesDepthStencil = false;
  1165. UpdatePassDepthStencil();
  1166. UpdatePipelineAttachmentFormats();
  1167. }
  1168. protected void UpdatePipelineAttachmentFormats()
  1169. {
  1170. Span<Silk.NET.Vulkan.Format> dstAttachmentFormats = _newState.Internal.AttachmentFormats.AsSpan();
  1171. FramebufferParams.AttachmentFormats.CopyTo(dstAttachmentFormats);
  1172. _newState.Internal.AttachmentIntegerFormatMask = FramebufferParams.AttachmentIntegerFormatMask;
  1173. _newState.Internal.LogicOpsAllowed = FramebufferParams.LogicOpsAllowed;
  1174. for (int i = FramebufferParams.AttachmentFormats.Length; i < dstAttachmentFormats.Length; i++)
  1175. {
  1176. dstAttachmentFormats[i] = 0;
  1177. }
  1178. _newState.ColorBlendAttachmentStateCount = (uint)(FramebufferParams.MaxColorAttachmentIndex + 1);
  1179. _newState.HasDepthStencil = FramebufferParams.HasDepthStencil;
  1180. _newState.SamplesCount = FramebufferParams.AttachmentSamples.Length != 0 ? FramebufferParams.AttachmentSamples[0] : 1;
  1181. }
  1182. protected unsafe void CreateRenderPass()
  1183. {
  1184. bool hasFramebuffer = FramebufferParams != null;
  1185. EndRenderPass();
  1186. if (!hasFramebuffer || FramebufferParams.AttachmentsCount == 0)
  1187. {
  1188. // Use the null framebuffer.
  1189. _nullRenderPass ??= new RenderPassHolder(Gd, Device, new RenderPassCacheKey(), FramebufferParams);
  1190. _rpHolder = _nullRenderPass;
  1191. _renderPass = _nullRenderPass.GetRenderPass();
  1192. _framebuffer = _nullRenderPass.GetFramebuffer(Gd, Cbs, FramebufferParams);
  1193. }
  1194. else
  1195. {
  1196. (_rpHolder, _framebuffer) = FramebufferParams.GetPassAndFramebuffer(Gd, Device, Cbs);
  1197. _renderPass = _rpHolder.GetRenderPass();
  1198. }
  1199. }
  1200. protected void SignalStateChange()
  1201. {
  1202. _graphicsStateDirty = true;
  1203. _computeStateDirty = true;
  1204. }
  1205. private void RecreateComputePipelineIfNeeded()
  1206. {
  1207. if (_computeStateDirty || Pbp != PipelineBindPoint.Compute)
  1208. {
  1209. CreatePipeline(PipelineBindPoint.Compute);
  1210. _computeStateDirty = false;
  1211. Pbp = PipelineBindPoint.Compute;
  1212. if (_bindingBarriersDirty)
  1213. {
  1214. // Stale barriers may have been activated by switching program. Emit any that are relevant.
  1215. _descriptorSetUpdater.InsertBindingBarriers(Cbs);
  1216. _bindingBarriersDirty = false;
  1217. }
  1218. }
  1219. Gd.Barriers.Flush(Cbs, _program, _feedbackLoop != 0, RenderPassActive, _rpHolder, EndRenderPassDelegate);
  1220. _descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, PipelineBindPoint.Compute);
  1221. }
  1222. private bool ChangeFeedbackLoop(FeedbackLoopAspects aspects)
  1223. {
  1224. if (_feedbackLoop != aspects)
  1225. {
  1226. if (Gd.Capabilities.SupportsDynamicAttachmentFeedbackLoop)
  1227. {
  1228. DynamicState.SetFeedbackLoop(aspects);
  1229. }
  1230. else
  1231. {
  1232. _newState.FeedbackLoopAspects = aspects;
  1233. }
  1234. _feedbackLoop = aspects;
  1235. return true;
  1236. }
  1237. return false;
  1238. }
  1239. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  1240. private bool UpdateFeedbackLoop()
  1241. {
  1242. List<TextureView> hazards = _descriptorSetUpdater.FeedbackLoopHazards;
  1243. if ((hazards?.Count ?? 0) > 0)
  1244. {
  1245. FeedbackLoopAspects aspects = 0;
  1246. foreach (TextureView view in hazards)
  1247. {
  1248. // May need to enforce feedback loop layout here in the future.
  1249. // Though technically, it should always work with the general layout.
  1250. if (view.Info.Format.IsDepthOrStencil())
  1251. {
  1252. if (_passWritesDepthStencil)
  1253. {
  1254. // If depth/stencil isn't written in the pass, it doesn't count as a feedback loop.
  1255. aspects |= FeedbackLoopAspects.Depth;
  1256. }
  1257. }
  1258. else
  1259. {
  1260. aspects |= FeedbackLoopAspects.Color;
  1261. }
  1262. }
  1263. return ChangeFeedbackLoop(aspects);
  1264. }
  1265. else if (_feedbackLoop != 0)
  1266. {
  1267. return ChangeFeedbackLoop(FeedbackLoopAspects.None);
  1268. }
  1269. return false;
  1270. }
  1271. private void UpdatePassDepthStencil()
  1272. {
  1273. if (!RenderPassActive)
  1274. {
  1275. _passWritesDepthStencil = false;
  1276. }
  1277. // Stencil test being enabled doesn't necessarily mean a write, but it's not critical to check.
  1278. _passWritesDepthStencil |= (_newState.DepthTestEnable && _newState.DepthWriteEnable) || _newState.StencilTestEnable;
  1279. }
  1280. private bool RecreateGraphicsPipelineIfNeeded()
  1281. {
  1282. if (AutoFlush.ShouldFlushDraw(DrawCount))
  1283. {
  1284. Gd.FlushAllCommands();
  1285. }
  1286. DynamicState.ReplayIfDirty(Gd, CommandBuffer);
  1287. if (_needsIndexBufferRebind && _indexBufferPattern == null)
  1288. {
  1289. _indexBuffer.BindIndexBuffer(Gd, Cbs);
  1290. _needsIndexBufferRebind = false;
  1291. }
  1292. if (_needsTransformFeedbackBuffersRebind)
  1293. {
  1294. PauseTransformFeedbackInternal();
  1295. for (int i = 0; i < Constants.MaxTransformFeedbackBuffers; i++)
  1296. {
  1297. _transformFeedbackBuffers[i].BindTransformFeedbackBuffer(Gd, Cbs, (uint)i);
  1298. }
  1299. _needsTransformFeedbackBuffersRebind = false;
  1300. }
  1301. if (_vertexBuffersDirty != 0)
  1302. {
  1303. while (_vertexBuffersDirty != 0)
  1304. {
  1305. int i = BitOperations.TrailingZeroCount(_vertexBuffersDirty);
  1306. _vertexBuffers[i].BindVertexBuffer(Gd, Cbs, (uint)i, ref _newState, _vertexBufferUpdater);
  1307. _vertexBuffersDirty &= ~(1UL << i);
  1308. }
  1309. _vertexBufferUpdater.Commit(Cbs);
  1310. }
  1311. if (_bindingBarriersDirty)
  1312. {
  1313. // Stale barriers may have been activated by switching program. Emit any that are relevant.
  1314. _descriptorSetUpdater.InsertBindingBarriers(Cbs);
  1315. _bindingBarriersDirty = false;
  1316. }
  1317. if (UpdateFeedbackLoop() || _graphicsStateDirty || Pbp != PipelineBindPoint.Graphics)
  1318. {
  1319. if (!CreatePipeline(PipelineBindPoint.Graphics))
  1320. {
  1321. return false;
  1322. }
  1323. _graphicsStateDirty = false;
  1324. Pbp = PipelineBindPoint.Graphics;
  1325. }
  1326. Gd.Barriers.Flush(Cbs, _program, _feedbackLoop != 0, RenderPassActive, _rpHolder, EndRenderPassDelegate);
  1327. _descriptorSetUpdater.UpdateAndBindDescriptorSets(Cbs, PipelineBindPoint.Graphics);
  1328. return true;
  1329. }
  1330. private bool CreatePipeline(PipelineBindPoint pbp)
  1331. {
  1332. // We can only create a pipeline if the have the shader stages set.
  1333. if (_newState.Stages != null)
  1334. {
  1335. if (pbp == PipelineBindPoint.Graphics && _renderPass == null)
  1336. {
  1337. CreateRenderPass();
  1338. }
  1339. if (!_program.IsLinked)
  1340. {
  1341. // Background compile failed, we likely can't create the pipeline because the shader is broken
  1342. // or the driver failed to compile it.
  1343. return false;
  1344. }
  1345. Auto<DisposablePipeline> pipeline = pbp == PipelineBindPoint.Compute
  1346. ? _newState.CreateComputePipeline(Gd, Device, _program, PipelineCache)
  1347. : _newState.CreateGraphicsPipeline(Gd, Device, _program, PipelineCache, _renderPass.Get(Cbs).Value);
  1348. if (pipeline == null)
  1349. {
  1350. // Host failed to create the pipeline, likely due to driver bugs.
  1351. return false;
  1352. }
  1353. ulong pipelineHandle = pipeline.GetUnsafe().Value.Handle;
  1354. if (_currentPipelineHandle != pipelineHandle)
  1355. {
  1356. _currentPipelineHandle = pipelineHandle;
  1357. Pipeline = pipeline;
  1358. PauseTransformFeedbackInternal();
  1359. Gd.Api.CmdBindPipeline(CommandBuffer, pbp, Pipeline.Get(Cbs).Value);
  1360. }
  1361. }
  1362. return true;
  1363. }
  1364. private unsafe void BeginRenderPass()
  1365. {
  1366. if (!RenderPassActive)
  1367. {
  1368. FramebufferParams.InsertLoadOpBarriers(Gd, Cbs);
  1369. Rect2D renderArea = new Rect2D(null, new Extent2D(FramebufferParams.Width, FramebufferParams.Height));
  1370. ClearValue clearValue = new ClearValue();
  1371. RenderPassBeginInfo renderPassBeginInfo = new RenderPassBeginInfo
  1372. {
  1373. SType = StructureType.RenderPassBeginInfo,
  1374. RenderPass = _renderPass.Get(Cbs).Value,
  1375. Framebuffer = _framebuffer.Get(Cbs).Value,
  1376. RenderArea = renderArea,
  1377. PClearValues = &clearValue,
  1378. ClearValueCount = 1,
  1379. };
  1380. Gd.Api.CmdBeginRenderPass(CommandBuffer, in renderPassBeginInfo, SubpassContents.Inline);
  1381. RenderPassActive = true;
  1382. }
  1383. }
  1384. public void EndRenderPass()
  1385. {
  1386. if (RenderPassActive)
  1387. {
  1388. FramebufferParams.AddStoreOpUsage();
  1389. PauseTransformFeedbackInternal();
  1390. Gd.Api.CmdEndRenderPass(CommandBuffer);
  1391. SignalRenderPassEnd();
  1392. RenderPassActive = false;
  1393. }
  1394. }
  1395. protected virtual void SignalRenderPassEnd()
  1396. {
  1397. }
  1398. private void PauseTransformFeedbackInternal()
  1399. {
  1400. if (_tfEnabled && _tfActive)
  1401. {
  1402. EndTransformFeedbackInternal();
  1403. _tfActive = false;
  1404. }
  1405. }
  1406. private void ResumeTransformFeedbackInternal()
  1407. {
  1408. if (_tfEnabled && !_tfActive)
  1409. {
  1410. BeginTransformFeedbackInternal();
  1411. _tfActive = true;
  1412. }
  1413. }
  1414. private unsafe void BeginTransformFeedbackInternal()
  1415. {
  1416. Gd.TransformFeedbackApi.CmdBeginTransformFeedback(CommandBuffer, 0, 0, null, null);
  1417. }
  1418. private unsafe void EndTransformFeedbackInternal()
  1419. {
  1420. Gd.TransformFeedbackApi.CmdEndTransformFeedback(CommandBuffer, 0, 0, null, null);
  1421. }
  1422. protected virtual void Dispose(bool disposing)
  1423. {
  1424. if (disposing)
  1425. {
  1426. _nullRenderPass?.Dispose();
  1427. _newState.Dispose();
  1428. _descriptorSetUpdater.Dispose();
  1429. _vertexBufferUpdater.Dispose();
  1430. for (int i = 0; i < _vertexBuffers.Length; i++)
  1431. {
  1432. _vertexBuffers[i].Dispose();
  1433. }
  1434. for (int i = 0; i < _transformFeedbackBuffers.Length; i++)
  1435. {
  1436. _transformFeedbackBuffers[i].Dispose();
  1437. }
  1438. Pipeline?.Dispose();
  1439. unsafe
  1440. {
  1441. Gd.Api.DestroyPipelineCache(Device, PipelineCache, null);
  1442. }
  1443. }
  1444. }
  1445. public void Dispose()
  1446. {
  1447. Dispose(true);
  1448. }
  1449. }
  1450. }