PipelineState.cs 29 KB

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