PipelineState.cs 28 KB

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