PipelineState.cs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737
  1. using Ryujinx.Common.Memory;
  2. using Silk.NET.Vulkan;
  3. using System;
  4. using System.Numerics;
  5. namespace Ryujinx.Graphics.Vulkan
  6. {
  7. struct PipelineState : IDisposable
  8. {
  9. private const int RequiredSubgroupSize = 32;
  10. public PipelineUid Internal;
  11. public float LineWidth
  12. {
  13. get => BitConverter.Int32BitsToSingle((int)((Internal.Id0 >> 0) & 0xFFFFFFFF));
  14. set => Internal.Id0 = (Internal.Id0 & 0xFFFFFFFF00000000) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 0);
  15. }
  16. public float DepthBiasClamp
  17. {
  18. get => BitConverter.Int32BitsToSingle((int)((Internal.Id0 >> 32) & 0xFFFFFFFF));
  19. set => Internal.Id0 = (Internal.Id0 & 0xFFFFFFFF) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 32);
  20. }
  21. public float DepthBiasConstantFactor
  22. {
  23. get => BitConverter.Int32BitsToSingle((int)((Internal.Id1 >> 0) & 0xFFFFFFFF));
  24. set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFFF00000000) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 0);
  25. }
  26. public float DepthBiasSlopeFactor
  27. {
  28. get => BitConverter.Int32BitsToSingle((int)((Internal.Id1 >> 32) & 0xFFFFFFFF));
  29. set => Internal.Id1 = (Internal.Id1 & 0xFFFFFFFF) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 32);
  30. }
  31. public uint StencilFrontCompareMask
  32. {
  33. get => (uint)((Internal.Id2 >> 0) & 0xFFFFFFFF);
  34. set => Internal.Id2 = (Internal.Id2 & 0xFFFFFFFF00000000) | ((ulong)value << 0);
  35. }
  36. public uint StencilFrontWriteMask
  37. {
  38. get => (uint)((Internal.Id2 >> 32) & 0xFFFFFFFF);
  39. set => Internal.Id2 = (Internal.Id2 & 0xFFFFFFFF) | ((ulong)value << 32);
  40. }
  41. public uint StencilFrontReference
  42. {
  43. get => (uint)((Internal.Id3 >> 0) & 0xFFFFFFFF);
  44. set => Internal.Id3 = (Internal.Id3 & 0xFFFFFFFF00000000) | ((ulong)value << 0);
  45. }
  46. public uint StencilBackCompareMask
  47. {
  48. get => (uint)((Internal.Id3 >> 32) & 0xFFFFFFFF);
  49. set => Internal.Id3 = (Internal.Id3 & 0xFFFFFFFF) | ((ulong)value << 32);
  50. }
  51. public uint StencilBackWriteMask
  52. {
  53. get => (uint)((Internal.Id4 >> 0) & 0xFFFFFFFF);
  54. set => Internal.Id4 = (Internal.Id4 & 0xFFFFFFFF00000000) | ((ulong)value << 0);
  55. }
  56. public uint StencilBackReference
  57. {
  58. get => (uint)((Internal.Id4 >> 32) & 0xFFFFFFFF);
  59. set => Internal.Id4 = (Internal.Id4 & 0xFFFFFFFF) | ((ulong)value << 32);
  60. }
  61. public float MinDepthBounds
  62. {
  63. get => BitConverter.Int32BitsToSingle((int)((Internal.Id5 >> 0) & 0xFFFFFFFF));
  64. set => Internal.Id5 = (Internal.Id5 & 0xFFFFFFFF00000000) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 0);
  65. }
  66. public float MaxDepthBounds
  67. {
  68. get => BitConverter.Int32BitsToSingle((int)((Internal.Id5 >> 32) & 0xFFFFFFFF));
  69. set => Internal.Id5 = (Internal.Id5 & 0xFFFFFFFF) | ((ulong)(uint)BitConverter.SingleToInt32Bits(value) << 32);
  70. }
  71. public PolygonMode PolygonMode
  72. {
  73. get => (PolygonMode)((Internal.Id6 >> 0) & 0x3FFFFFFF);
  74. set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFFFC0000000) | ((ulong)value << 0);
  75. }
  76. public uint StagesCount
  77. {
  78. get => (byte)((Internal.Id6 >> 30) & 0xFF);
  79. set => Internal.Id6 = (Internal.Id6 & 0xFFFFFFC03FFFFFFF) | ((ulong)value << 30);
  80. }
  81. public uint VertexAttributeDescriptionsCount
  82. {
  83. get => (byte)((Internal.Id6 >> 38) & 0xFF);
  84. set => Internal.Id6 = (Internal.Id6 & 0xFFFFC03FFFFFFFFF) | ((ulong)value << 38);
  85. }
  86. public uint VertexBindingDescriptionsCount
  87. {
  88. get => (byte)((Internal.Id6 >> 46) & 0xFF);
  89. set => Internal.Id6 = (Internal.Id6 & 0xFFC03FFFFFFFFFFF) | ((ulong)value << 46);
  90. }
  91. public uint ViewportsCount
  92. {
  93. get => (byte)((Internal.Id6 >> 54) & 0xFF);
  94. set => Internal.Id6 = (Internal.Id6 & 0xC03FFFFFFFFFFFFF) | ((ulong)value << 54);
  95. }
  96. public uint ScissorsCount
  97. {
  98. get => (byte)((Internal.Id7 >> 0) & 0xFF);
  99. set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFFFFFFF00) | ((ulong)value << 0);
  100. }
  101. public uint ColorBlendAttachmentStateCount
  102. {
  103. get => (byte)((Internal.Id7 >> 8) & 0xFF);
  104. set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFFFFF00FF) | ((ulong)value << 8);
  105. }
  106. public PrimitiveTopology Topology
  107. {
  108. get => (PrimitiveTopology)((Internal.Id7 >> 16) & 0xF);
  109. set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFFFF0FFFF) | ((ulong)value << 16);
  110. }
  111. public LogicOp LogicOp
  112. {
  113. get => (LogicOp)((Internal.Id7 >> 20) & 0xF);
  114. set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFFF0FFFFF) | ((ulong)value << 20);
  115. }
  116. public CompareOp DepthCompareOp
  117. {
  118. get => (CompareOp)((Internal.Id7 >> 24) & 0x7);
  119. set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFF8FFFFFF) | ((ulong)value << 24);
  120. }
  121. public StencilOp StencilFrontFailOp
  122. {
  123. get => (StencilOp)((Internal.Id7 >> 27) & 0x7);
  124. set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFFC7FFFFFF) | ((ulong)value << 27);
  125. }
  126. public StencilOp StencilFrontPassOp
  127. {
  128. get => (StencilOp)((Internal.Id7 >> 30) & 0x7);
  129. set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFFE3FFFFFFF) | ((ulong)value << 30);
  130. }
  131. public StencilOp StencilFrontDepthFailOp
  132. {
  133. get => (StencilOp)((Internal.Id7 >> 33) & 0x7);
  134. set => Internal.Id7 = (Internal.Id7 & 0xFFFFFFF1FFFFFFFF) | ((ulong)value << 33);
  135. }
  136. public CompareOp StencilFrontCompareOp
  137. {
  138. get => (CompareOp)((Internal.Id7 >> 36) & 0x7);
  139. set => Internal.Id7 = (Internal.Id7 & 0xFFFFFF8FFFFFFFFF) | ((ulong)value << 36);
  140. }
  141. public StencilOp StencilBackFailOp
  142. {
  143. get => (StencilOp)((Internal.Id7 >> 39) & 0x7);
  144. set => Internal.Id7 = (Internal.Id7 & 0xFFFFFC7FFFFFFFFF) | ((ulong)value << 39);
  145. }
  146. public StencilOp StencilBackPassOp
  147. {
  148. get => (StencilOp)((Internal.Id7 >> 42) & 0x7);
  149. set => Internal.Id7 = (Internal.Id7 & 0xFFFFE3FFFFFFFFFF) | ((ulong)value << 42);
  150. }
  151. public StencilOp StencilBackDepthFailOp
  152. {
  153. get => (StencilOp)((Internal.Id7 >> 45) & 0x7);
  154. set => Internal.Id7 = (Internal.Id7 & 0xFFFF1FFFFFFFFFFF) | ((ulong)value << 45);
  155. }
  156. public CompareOp StencilBackCompareOp
  157. {
  158. get => (CompareOp)((Internal.Id7 >> 48) & 0x7);
  159. set => Internal.Id7 = (Internal.Id7 & 0xFFF8FFFFFFFFFFFF) | ((ulong)value << 48);
  160. }
  161. public CullModeFlags CullMode
  162. {
  163. get => (CullModeFlags)((Internal.Id7 >> 51) & 0x3);
  164. set => Internal.Id7 = (Internal.Id7 & 0xFFE7FFFFFFFFFFFF) | ((ulong)value << 51);
  165. }
  166. public bool PrimitiveRestartEnable
  167. {
  168. get => ((Internal.Id7 >> 53) & 0x1) != 0UL;
  169. set => Internal.Id7 = (Internal.Id7 & 0xFFDFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 53);
  170. }
  171. public bool DepthClampEnable
  172. {
  173. get => ((Internal.Id7 >> 54) & 0x1) != 0UL;
  174. set => Internal.Id7 = (Internal.Id7 & 0xFFBFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 54);
  175. }
  176. public bool RasterizerDiscardEnable
  177. {
  178. get => ((Internal.Id7 >> 55) & 0x1) != 0UL;
  179. set => Internal.Id7 = (Internal.Id7 & 0xFF7FFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 55);
  180. }
  181. public FrontFace FrontFace
  182. {
  183. get => (FrontFace)((Internal.Id7 >> 56) & 0x1);
  184. set => Internal.Id7 = (Internal.Id7 & 0xFEFFFFFFFFFFFFFF) | ((ulong)value << 56);
  185. }
  186. public bool DepthBiasEnable
  187. {
  188. get => ((Internal.Id7 >> 57) & 0x1) != 0UL;
  189. set => Internal.Id7 = (Internal.Id7 & 0xFDFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 57);
  190. }
  191. public bool DepthTestEnable
  192. {
  193. get => ((Internal.Id7 >> 58) & 0x1) != 0UL;
  194. set => Internal.Id7 = (Internal.Id7 & 0xFBFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 58);
  195. }
  196. public bool DepthWriteEnable
  197. {
  198. get => ((Internal.Id7 >> 59) & 0x1) != 0UL;
  199. set => Internal.Id7 = (Internal.Id7 & 0xF7FFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 59);
  200. }
  201. public bool DepthBoundsTestEnable
  202. {
  203. get => ((Internal.Id7 >> 60) & 0x1) != 0UL;
  204. set => Internal.Id7 = (Internal.Id7 & 0xEFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 60);
  205. }
  206. public bool StencilTestEnable
  207. {
  208. get => ((Internal.Id7 >> 61) & 0x1) != 0UL;
  209. set => Internal.Id7 = (Internal.Id7 & 0xDFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 61);
  210. }
  211. public bool LogicOpEnable
  212. {
  213. get => ((Internal.Id7 >> 62) & 0x1) != 0UL;
  214. set => Internal.Id7 = (Internal.Id7 & 0xBFFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 62);
  215. }
  216. public bool HasDepthStencil
  217. {
  218. get => ((Internal.Id7 >> 63) & 0x1) != 0UL;
  219. set => Internal.Id7 = (Internal.Id7 & 0x7FFFFFFFFFFFFFFF) | ((value ? 1UL : 0UL) << 63);
  220. }
  221. public uint PatchControlPoints
  222. {
  223. get => (uint)((Internal.Id8 >> 0) & 0xFFFFFFFF);
  224. set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFF00000000) | ((ulong)value << 0);
  225. }
  226. public uint SamplesCount
  227. {
  228. get => (uint)((Internal.Id8 >> 32) & 0xFFFFFFFF);
  229. set => Internal.Id8 = (Internal.Id8 & 0xFFFFFFFF) | ((ulong)value << 32);
  230. }
  231. public bool AlphaToCoverageEnable
  232. {
  233. get => ((Internal.Id9 >> 0) & 0x1) != 0UL;
  234. set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFFE) | ((value ? 1UL : 0UL) << 0);
  235. }
  236. public bool AlphaToOneEnable
  237. {
  238. get => ((Internal.Id9 >> 1) & 0x1) != 0UL;
  239. set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFFD) | ((value ? 1UL : 0UL) << 1);
  240. }
  241. public bool AdvancedBlendSrcPreMultiplied
  242. {
  243. get => ((Internal.Id9 >> 2) & 0x1) != 0UL;
  244. set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFFB) | ((value ? 1UL : 0UL) << 2);
  245. }
  246. public bool AdvancedBlendDstPreMultiplied
  247. {
  248. get => ((Internal.Id9 >> 3) & 0x1) != 0UL;
  249. set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFF7) | ((value ? 1UL : 0UL) << 3);
  250. }
  251. public BlendOverlapEXT AdvancedBlendOverlap
  252. {
  253. get => (BlendOverlapEXT)((Internal.Id9 >> 4) & 0x3);
  254. set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFCF) | ((ulong)value << 4);
  255. }
  256. public bool DepthMode
  257. {
  258. get => ((Internal.Id9 >> 6) & 0x1) != 0UL;
  259. set => Internal.Id9 = (Internal.Id9 & 0xFFFFFFFFFFFFFFBF) | ((value ? 1UL : 0UL) << 6);
  260. }
  261. public NativeArray<PipelineShaderStageCreateInfo> Stages;
  262. public NativeArray<PipelineShaderStageRequiredSubgroupSizeCreateInfoEXT> StageRequiredSubgroupSizes;
  263. public PipelineLayout PipelineLayout;
  264. public SpecData SpecializationData;
  265. private Array32<VertexInputAttributeDescription> _vertexAttributeDescriptions2;
  266. public void Initialize()
  267. {
  268. Stages = new NativeArray<PipelineShaderStageCreateInfo>(Constants.MaxShaderStages);
  269. StageRequiredSubgroupSizes = new NativeArray<PipelineShaderStageRequiredSubgroupSizeCreateInfoEXT>(Constants.MaxShaderStages);
  270. for (int index = 0; index < Constants.MaxShaderStages; index++)
  271. {
  272. StageRequiredSubgroupSizes[index] = new PipelineShaderStageRequiredSubgroupSizeCreateInfoEXT()
  273. {
  274. SType = StructureType.PipelineShaderStageRequiredSubgroupSizeCreateInfoExt,
  275. RequiredSubgroupSize = RequiredSubgroupSize
  276. };
  277. }
  278. AdvancedBlendSrcPreMultiplied = true;
  279. AdvancedBlendDstPreMultiplied = true;
  280. AdvancedBlendOverlap = BlendOverlapEXT.UncorrelatedExt;
  281. LineWidth = 1f;
  282. SamplesCount = 1;
  283. DepthMode = true;
  284. }
  285. public unsafe Auto<DisposablePipeline> CreateComputePipeline(
  286. VulkanRenderer gd,
  287. Device device,
  288. ShaderCollection program,
  289. PipelineCache cache)
  290. {
  291. if (program.TryGetComputePipeline(ref SpecializationData, out var pipeline))
  292. {
  293. return pipeline;
  294. }
  295. if (gd.Capabilities.SupportsSubgroupSizeControl)
  296. {
  297. UpdateStageRequiredSubgroupSizes(gd, 1);
  298. }
  299. var pipelineCreateInfo = new ComputePipelineCreateInfo()
  300. {
  301. SType = StructureType.ComputePipelineCreateInfo,
  302. Stage = Stages[0],
  303. BasePipelineIndex = -1,
  304. Layout = PipelineLayout
  305. };
  306. Pipeline pipelineHandle = default;
  307. bool hasSpec = program.SpecDescriptions != null;
  308. var desc = hasSpec ? program.SpecDescriptions[0] : SpecDescription.Empty;
  309. if (hasSpec && SpecializationData.Length < (int)desc.Info.DataSize)
  310. {
  311. throw new InvalidOperationException("Specialization data size does not match description");
  312. }
  313. fixed (SpecializationInfo* info = &desc.Info)
  314. fixed (SpecializationMapEntry* map = desc.Map)
  315. fixed (byte* data = SpecializationData.Span)
  316. {
  317. if (hasSpec)
  318. {
  319. info->PMapEntries = map;
  320. info->PData = data;
  321. pipelineCreateInfo.Stage.PSpecializationInfo = info;
  322. }
  323. gd.Api.CreateComputePipelines(device, cache, 1, &pipelineCreateInfo, null, &pipelineHandle).ThrowOnError();
  324. }
  325. pipeline = new Auto<DisposablePipeline>(new DisposablePipeline(gd.Api, device, pipelineHandle));
  326. program.AddComputePipeline(ref SpecializationData, pipeline);
  327. return pipeline;
  328. }
  329. public unsafe Auto<DisposablePipeline> CreateGraphicsPipeline(
  330. VulkanRenderer gd,
  331. Device device,
  332. ShaderCollection program,
  333. PipelineCache cache,
  334. RenderPass renderPass)
  335. {
  336. if (program.TryGetGraphicsPipeline(ref Internal, out var pipeline))
  337. {
  338. return pipeline;
  339. }
  340. Pipeline pipelineHandle = default;
  341. bool isMoltenVk = gd.IsMoltenVk;
  342. if (isMoltenVk)
  343. {
  344. UpdateVertexAttributeDescriptions(gd);
  345. }
  346. fixed (VertexInputAttributeDescription* pVertexAttributeDescriptions = &Internal.VertexAttributeDescriptions[0])
  347. fixed (VertexInputAttributeDescription* pVertexAttributeDescriptions2 = &_vertexAttributeDescriptions2[0])
  348. fixed (VertexInputBindingDescription* pVertexBindingDescriptions = &Internal.VertexBindingDescriptions[0])
  349. fixed (Viewport* pViewports = &Internal.Viewports[0])
  350. fixed (Rect2D* pScissors = &Internal.Scissors[0])
  351. fixed (PipelineColorBlendAttachmentState* pColorBlendAttachmentState = &Internal.ColorBlendAttachmentState[0])
  352. {
  353. var vertexInputState = new PipelineVertexInputStateCreateInfo
  354. {
  355. SType = StructureType.PipelineVertexInputStateCreateInfo,
  356. VertexAttributeDescriptionCount = VertexAttributeDescriptionsCount,
  357. PVertexAttributeDescriptions = isMoltenVk ? pVertexAttributeDescriptions2 : pVertexAttributeDescriptions,
  358. VertexBindingDescriptionCount = VertexBindingDescriptionsCount,
  359. PVertexBindingDescriptions = pVertexBindingDescriptions
  360. };
  361. bool primitiveRestartEnable = PrimitiveRestartEnable;
  362. bool topologySupportsRestart;
  363. if (gd.Capabilities.SupportsPrimitiveTopologyListRestart)
  364. {
  365. topologySupportsRestart = gd.Capabilities.SupportsPrimitiveTopologyPatchListRestart || Topology != PrimitiveTopology.PatchList;
  366. }
  367. else
  368. {
  369. topologySupportsRestart = Topology == PrimitiveTopology.LineStrip ||
  370. Topology == PrimitiveTopology.TriangleStrip ||
  371. Topology == PrimitiveTopology.TriangleFan ||
  372. Topology == PrimitiveTopology.LineStripWithAdjacency ||
  373. Topology == PrimitiveTopology.TriangleStripWithAdjacency;
  374. }
  375. primitiveRestartEnable &= topologySupportsRestart;
  376. var inputAssemblyState = new PipelineInputAssemblyStateCreateInfo()
  377. {
  378. SType = StructureType.PipelineInputAssemblyStateCreateInfo,
  379. PrimitiveRestartEnable = primitiveRestartEnable,
  380. Topology = Topology
  381. };
  382. var tessellationState = new PipelineTessellationStateCreateInfo()
  383. {
  384. SType = StructureType.PipelineTessellationStateCreateInfo,
  385. PatchControlPoints = PatchControlPoints
  386. };
  387. var rasterizationState = new PipelineRasterizationStateCreateInfo()
  388. {
  389. SType = StructureType.PipelineRasterizationStateCreateInfo,
  390. DepthClampEnable = DepthClampEnable,
  391. RasterizerDiscardEnable = RasterizerDiscardEnable,
  392. PolygonMode = PolygonMode,
  393. LineWidth = LineWidth,
  394. CullMode = CullMode,
  395. FrontFace = FrontFace,
  396. DepthBiasEnable = DepthBiasEnable,
  397. DepthBiasClamp = DepthBiasClamp,
  398. DepthBiasConstantFactor = DepthBiasConstantFactor,
  399. DepthBiasSlopeFactor = DepthBiasSlopeFactor
  400. };
  401. var viewportState = new PipelineViewportStateCreateInfo()
  402. {
  403. SType = StructureType.PipelineViewportStateCreateInfo,
  404. ViewportCount = ViewportsCount,
  405. PViewports = pViewports,
  406. ScissorCount = ScissorsCount,
  407. PScissors = pScissors
  408. };
  409. if (gd.Capabilities.SupportsDepthClipControl)
  410. {
  411. var viewportDepthClipControlState = new PipelineViewportDepthClipControlCreateInfoEXT()
  412. {
  413. SType = StructureType.PipelineViewportDepthClipControlCreateInfoExt,
  414. NegativeOneToOne = DepthMode
  415. };
  416. viewportState.PNext = &viewportDepthClipControlState;
  417. }
  418. var multisampleState = new PipelineMultisampleStateCreateInfo
  419. {
  420. SType = StructureType.PipelineMultisampleStateCreateInfo,
  421. SampleShadingEnable = false,
  422. RasterizationSamples = TextureStorage.ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, SamplesCount),
  423. MinSampleShading = 1,
  424. AlphaToCoverageEnable = AlphaToCoverageEnable,
  425. AlphaToOneEnable = AlphaToOneEnable
  426. };
  427. var stencilFront = new StencilOpState(
  428. StencilFrontFailOp,
  429. StencilFrontPassOp,
  430. StencilFrontDepthFailOp,
  431. StencilFrontCompareOp,
  432. StencilFrontCompareMask,
  433. StencilFrontWriteMask,
  434. StencilFrontReference);
  435. var stencilBack = new StencilOpState(
  436. StencilBackFailOp,
  437. StencilBackPassOp,
  438. StencilBackDepthFailOp,
  439. StencilBackCompareOp,
  440. StencilBackCompareMask,
  441. StencilBackWriteMask,
  442. StencilBackReference);
  443. var depthStencilState = new PipelineDepthStencilStateCreateInfo()
  444. {
  445. SType = StructureType.PipelineDepthStencilStateCreateInfo,
  446. DepthTestEnable = DepthTestEnable,
  447. DepthWriteEnable = DepthWriteEnable,
  448. DepthCompareOp = DepthCompareOp,
  449. DepthBoundsTestEnable = DepthBoundsTestEnable,
  450. StencilTestEnable = StencilTestEnable,
  451. Front = stencilFront,
  452. Back = stencilBack,
  453. MinDepthBounds = MinDepthBounds,
  454. MaxDepthBounds = MaxDepthBounds
  455. };
  456. uint blendEnables = 0;
  457. if (gd.IsMoltenVk && Internal.AttachmentIntegerFormatMask != 0)
  458. {
  459. // Blend can't be enabled for integer formats, so let's make sure it is disabled.
  460. uint attachmentIntegerFormatMask = Internal.AttachmentIntegerFormatMask;
  461. while (attachmentIntegerFormatMask != 0)
  462. {
  463. int i = BitOperations.TrailingZeroCount(attachmentIntegerFormatMask);
  464. if (Internal.ColorBlendAttachmentState[i].BlendEnable)
  465. {
  466. blendEnables |= 1u << i;
  467. }
  468. Internal.ColorBlendAttachmentState[i].BlendEnable = false;
  469. attachmentIntegerFormatMask &= ~(1u << i);
  470. }
  471. }
  472. var colorBlendState = new PipelineColorBlendStateCreateInfo()
  473. {
  474. SType = StructureType.PipelineColorBlendStateCreateInfo,
  475. LogicOpEnable = LogicOpEnable,
  476. LogicOp = LogicOp,
  477. AttachmentCount = ColorBlendAttachmentStateCount,
  478. PAttachments = pColorBlendAttachmentState
  479. };
  480. PipelineColorBlendAdvancedStateCreateInfoEXT colorBlendAdvancedState;
  481. if (!AdvancedBlendSrcPreMultiplied ||
  482. !AdvancedBlendDstPreMultiplied ||
  483. AdvancedBlendOverlap != BlendOverlapEXT.UncorrelatedExt)
  484. {
  485. colorBlendAdvancedState = new PipelineColorBlendAdvancedStateCreateInfoEXT()
  486. {
  487. SType = StructureType.PipelineColorBlendAdvancedStateCreateInfoExt,
  488. SrcPremultiplied = AdvancedBlendSrcPreMultiplied,
  489. DstPremultiplied = AdvancedBlendDstPreMultiplied,
  490. BlendOverlap = AdvancedBlendOverlap
  491. };
  492. colorBlendState.PNext = &colorBlendAdvancedState;
  493. }
  494. bool supportsExtDynamicState = gd.Capabilities.SupportsExtendedDynamicState;
  495. int dynamicStatesCount = supportsExtDynamicState ? 9 : 8;
  496. DynamicState* dynamicStates = stackalloc DynamicState[dynamicStatesCount];
  497. dynamicStates[0] = DynamicState.Viewport;
  498. dynamicStates[1] = DynamicState.Scissor;
  499. dynamicStates[2] = DynamicState.DepthBias;
  500. dynamicStates[3] = DynamicState.DepthBounds;
  501. dynamicStates[4] = DynamicState.StencilCompareMask;
  502. dynamicStates[5] = DynamicState.StencilWriteMask;
  503. dynamicStates[6] = DynamicState.StencilReference;
  504. dynamicStates[7] = DynamicState.BlendConstants;
  505. if (supportsExtDynamicState)
  506. {
  507. dynamicStates[8] = DynamicState.VertexInputBindingStrideExt;
  508. }
  509. var pipelineDynamicStateCreateInfo = new PipelineDynamicStateCreateInfo()
  510. {
  511. SType = StructureType.PipelineDynamicStateCreateInfo,
  512. DynamicStateCount = (uint)dynamicStatesCount,
  513. PDynamicStates = dynamicStates
  514. };
  515. if (gd.Capabilities.SupportsSubgroupSizeControl)
  516. {
  517. UpdateStageRequiredSubgroupSizes(gd, (int)StagesCount);
  518. }
  519. var pipelineCreateInfo = new GraphicsPipelineCreateInfo()
  520. {
  521. SType = StructureType.GraphicsPipelineCreateInfo,
  522. StageCount = StagesCount,
  523. PStages = Stages.Pointer,
  524. PVertexInputState = &vertexInputState,
  525. PInputAssemblyState = &inputAssemblyState,
  526. PTessellationState = &tessellationState,
  527. PViewportState = &viewportState,
  528. PRasterizationState = &rasterizationState,
  529. PMultisampleState = &multisampleState,
  530. PDepthStencilState = &depthStencilState,
  531. PColorBlendState = &colorBlendState,
  532. PDynamicState = &pipelineDynamicStateCreateInfo,
  533. Layout = PipelineLayout,
  534. RenderPass = renderPass,
  535. BasePipelineIndex = -1
  536. };
  537. gd.Api.CreateGraphicsPipelines(device, cache, 1, &pipelineCreateInfo, null, &pipelineHandle).ThrowOnError();
  538. // Restore previous blend enable values if we changed it.
  539. while (blendEnables != 0)
  540. {
  541. int i = BitOperations.TrailingZeroCount(blendEnables);
  542. Internal.ColorBlendAttachmentState[i].BlendEnable = true;
  543. blendEnables &= ~(1u << i);
  544. }
  545. }
  546. pipeline = new Auto<DisposablePipeline>(new DisposablePipeline(gd.Api, device, pipelineHandle));
  547. program.AddGraphicsPipeline(ref Internal, pipeline);
  548. return pipeline;
  549. }
  550. private unsafe void UpdateStageRequiredSubgroupSizes(VulkanRenderer gd, int count)
  551. {
  552. for (int index = 0; index < count; index++)
  553. {
  554. bool canUseExplicitSubgroupSize =
  555. (gd.Capabilities.RequiredSubgroupSizeStages & Stages[index].Stage) != 0 &&
  556. gd.Capabilities.MinSubgroupSize <= RequiredSubgroupSize &&
  557. gd.Capabilities.MaxSubgroupSize >= RequiredSubgroupSize;
  558. Stages[index].PNext = canUseExplicitSubgroupSize ? StageRequiredSubgroupSizes.Pointer + index : null;
  559. }
  560. }
  561. private void UpdateVertexAttributeDescriptions(VulkanRenderer gd)
  562. {
  563. // Vertex attributes exceeding the stride are invalid.
  564. // In metal, they cause glitches with the vertex shader fetching incorrect values.
  565. // To work around this, we reduce the format to something that doesn't exceed the stride if possible.
  566. // The assumption is that the exceeding components are not actually accessed on the shader.
  567. for (int index = 0; index < VertexAttributeDescriptionsCount; index++)
  568. {
  569. var attribute = Internal.VertexAttributeDescriptions[index];
  570. int vbIndex = GetVertexBufferIndex(attribute.Binding);
  571. if (vbIndex >= 0)
  572. {
  573. ref var vb = ref Internal.VertexBindingDescriptions[vbIndex];
  574. Format format = attribute.Format;
  575. while (vb.Stride != 0 && attribute.Offset + FormatTable.GetAttributeFormatSize(format) > vb.Stride)
  576. {
  577. Format newFormat = FormatTable.DropLastComponent(format);
  578. if (newFormat == format)
  579. {
  580. // That case means we failed to find a format that fits within the stride,
  581. // so just restore the original format and give up.
  582. format = attribute.Format;
  583. break;
  584. }
  585. format = newFormat;
  586. }
  587. if (attribute.Format != format && gd.FormatCapabilities.BufferFormatSupports(FormatFeatureFlags.VertexBufferBit, format))
  588. {
  589. attribute.Format = format;
  590. }
  591. }
  592. _vertexAttributeDescriptions2[index] = attribute;
  593. }
  594. }
  595. private int GetVertexBufferIndex(uint binding)
  596. {
  597. for (int index = 0; index < VertexBindingDescriptionsCount; index++)
  598. {
  599. if (Internal.VertexBindingDescriptions[index].Binding == binding)
  600. {
  601. return index;
  602. }
  603. }
  604. return -1;
  605. }
  606. public void Dispose()
  607. {
  608. Stages.Dispose();
  609. StageRequiredSubgroupSizes.Dispose();
  610. }
  611. }
  612. }