PipelineState.cs 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  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 NativeArray<PipelineShaderStageCreateInfo> Stages;
  256. public NativeArray<PipelineShaderStageRequiredSubgroupSizeCreateInfoEXT> StageRequiredSubgroupSizes;
  257. public PipelineLayout PipelineLayout;
  258. public SpecData SpecializationData;
  259. private Array32<VertexInputAttributeDescription> _vertexAttributeDescriptions2;
  260. public void Initialize()
  261. {
  262. Stages = new NativeArray<PipelineShaderStageCreateInfo>(Constants.MaxShaderStages);
  263. StageRequiredSubgroupSizes = new NativeArray<PipelineShaderStageRequiredSubgroupSizeCreateInfoEXT>(Constants.MaxShaderStages);
  264. for (int index = 0; index < Constants.MaxShaderStages; index++)
  265. {
  266. StageRequiredSubgroupSizes[index] = new PipelineShaderStageRequiredSubgroupSizeCreateInfoEXT()
  267. {
  268. SType = StructureType.PipelineShaderStageRequiredSubgroupSizeCreateInfoExt,
  269. RequiredSubgroupSize = RequiredSubgroupSize
  270. };
  271. }
  272. AdvancedBlendSrcPreMultiplied = true;
  273. AdvancedBlendDstPreMultiplied = true;
  274. AdvancedBlendOverlap = BlendOverlapEXT.UncorrelatedExt;
  275. LineWidth = 1f;
  276. SamplesCount = 1;
  277. }
  278. public unsafe Auto<DisposablePipeline> CreateComputePipeline(
  279. VulkanRenderer gd,
  280. Device device,
  281. ShaderCollection program,
  282. PipelineCache cache)
  283. {
  284. if (program.TryGetComputePipeline(ref SpecializationData, out var pipeline))
  285. {
  286. return pipeline;
  287. }
  288. if (gd.Capabilities.SupportsSubgroupSizeControl)
  289. {
  290. UpdateStageRequiredSubgroupSizes(gd, 1);
  291. }
  292. var pipelineCreateInfo = new ComputePipelineCreateInfo()
  293. {
  294. SType = StructureType.ComputePipelineCreateInfo,
  295. Stage = Stages[0],
  296. BasePipelineIndex = -1,
  297. Layout = PipelineLayout
  298. };
  299. Pipeline pipelineHandle = default;
  300. bool hasSpec = program.SpecDescriptions != null;
  301. var desc = hasSpec ? program.SpecDescriptions[0] : SpecDescription.Empty;
  302. if (hasSpec && SpecializationData.Length < (int)desc.Info.DataSize)
  303. {
  304. throw new InvalidOperationException("Specialization data size does not match description");
  305. }
  306. fixed (SpecializationInfo* info = &desc.Info)
  307. fixed (SpecializationMapEntry* map = desc.Map)
  308. fixed (byte* data = SpecializationData.Span)
  309. {
  310. if (hasSpec)
  311. {
  312. info->PMapEntries = map;
  313. info->PData = data;
  314. pipelineCreateInfo.Stage.PSpecializationInfo = info;
  315. }
  316. gd.Api.CreateComputePipelines(device, cache, 1, &pipelineCreateInfo, null, &pipelineHandle).ThrowOnError();
  317. }
  318. pipeline = new Auto<DisposablePipeline>(new DisposablePipeline(gd.Api, device, pipelineHandle));
  319. program.AddComputePipeline(ref SpecializationData, pipeline);
  320. return pipeline;
  321. }
  322. public unsafe Auto<DisposablePipeline> CreateGraphicsPipeline(
  323. VulkanRenderer gd,
  324. Device device,
  325. ShaderCollection program,
  326. PipelineCache cache,
  327. RenderPass renderPass)
  328. {
  329. if (program.TryGetGraphicsPipeline(ref Internal, out var pipeline))
  330. {
  331. return pipeline;
  332. }
  333. Pipeline pipelineHandle = default;
  334. bool isMoltenVk = gd.IsMoltenVk;
  335. if (isMoltenVk)
  336. {
  337. UpdateVertexAttributeDescriptions();
  338. }
  339. fixed (VertexInputAttributeDescription* pVertexAttributeDescriptions = &Internal.VertexAttributeDescriptions[0])
  340. fixed (VertexInputAttributeDescription* pVertexAttributeDescriptions2 = &_vertexAttributeDescriptions2[0])
  341. fixed (VertexInputBindingDescription* pVertexBindingDescriptions = &Internal.VertexBindingDescriptions[0])
  342. fixed (Viewport* pViewports = &Internal.Viewports[0])
  343. fixed (Rect2D* pScissors = &Internal.Scissors[0])
  344. fixed (PipelineColorBlendAttachmentState* pColorBlendAttachmentState = &Internal.ColorBlendAttachmentState[0])
  345. {
  346. var vertexInputState = new PipelineVertexInputStateCreateInfo
  347. {
  348. SType = StructureType.PipelineVertexInputStateCreateInfo,
  349. VertexAttributeDescriptionCount = VertexAttributeDescriptionsCount,
  350. PVertexAttributeDescriptions = isMoltenVk ? pVertexAttributeDescriptions2 : pVertexAttributeDescriptions,
  351. VertexBindingDescriptionCount = VertexBindingDescriptionsCount,
  352. PVertexBindingDescriptions = pVertexBindingDescriptions
  353. };
  354. bool primitiveRestartEnable = PrimitiveRestartEnable;
  355. bool topologySupportsRestart;
  356. if (gd.Capabilities.SupportsPrimitiveTopologyListRestart)
  357. {
  358. topologySupportsRestart = gd.Capabilities.SupportsPrimitiveTopologyPatchListRestart || Topology != PrimitiveTopology.PatchList;
  359. }
  360. else
  361. {
  362. topologySupportsRestart = Topology == PrimitiveTopology.LineStrip ||
  363. Topology == PrimitiveTopology.TriangleStrip ||
  364. Topology == PrimitiveTopology.TriangleFan ||
  365. Topology == PrimitiveTopology.LineStripWithAdjacency ||
  366. Topology == PrimitiveTopology.TriangleStripWithAdjacency;
  367. }
  368. primitiveRestartEnable &= topologySupportsRestart;
  369. var inputAssemblyState = new PipelineInputAssemblyStateCreateInfo()
  370. {
  371. SType = StructureType.PipelineInputAssemblyStateCreateInfo,
  372. PrimitiveRestartEnable = primitiveRestartEnable,
  373. Topology = Topology
  374. };
  375. var tessellationState = new PipelineTessellationStateCreateInfo()
  376. {
  377. SType = StructureType.PipelineTessellationStateCreateInfo,
  378. PatchControlPoints = PatchControlPoints
  379. };
  380. var rasterizationState = new PipelineRasterizationStateCreateInfo()
  381. {
  382. SType = StructureType.PipelineRasterizationStateCreateInfo,
  383. DepthClampEnable = DepthClampEnable,
  384. RasterizerDiscardEnable = RasterizerDiscardEnable,
  385. PolygonMode = PolygonMode,
  386. LineWidth = LineWidth,
  387. CullMode = CullMode,
  388. FrontFace = FrontFace,
  389. DepthBiasEnable = DepthBiasEnable,
  390. DepthBiasClamp = DepthBiasClamp,
  391. DepthBiasConstantFactor = DepthBiasConstantFactor,
  392. DepthBiasSlopeFactor = DepthBiasSlopeFactor
  393. };
  394. var viewportState = new PipelineViewportStateCreateInfo()
  395. {
  396. SType = StructureType.PipelineViewportStateCreateInfo,
  397. ViewportCount = ViewportsCount,
  398. PViewports = pViewports,
  399. ScissorCount = ScissorsCount,
  400. PScissors = pScissors
  401. };
  402. var multisampleState = new PipelineMultisampleStateCreateInfo
  403. {
  404. SType = StructureType.PipelineMultisampleStateCreateInfo,
  405. SampleShadingEnable = false,
  406. RasterizationSamples = TextureStorage.ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, SamplesCount),
  407. MinSampleShading = 1,
  408. AlphaToCoverageEnable = AlphaToCoverageEnable,
  409. AlphaToOneEnable = AlphaToOneEnable
  410. };
  411. var stencilFront = new StencilOpState(
  412. StencilFrontFailOp,
  413. StencilFrontPassOp,
  414. StencilFrontDepthFailOp,
  415. StencilFrontCompareOp,
  416. StencilFrontCompareMask,
  417. StencilFrontWriteMask,
  418. StencilFrontReference);
  419. var stencilBack = new StencilOpState(
  420. StencilBackFailOp,
  421. StencilBackPassOp,
  422. StencilBackDepthFailOp,
  423. StencilBackCompareOp,
  424. StencilBackCompareMask,
  425. StencilBackWriteMask,
  426. StencilBackReference);
  427. var depthStencilState = new PipelineDepthStencilStateCreateInfo()
  428. {
  429. SType = StructureType.PipelineDepthStencilStateCreateInfo,
  430. DepthTestEnable = DepthTestEnable,
  431. DepthWriteEnable = DepthWriteEnable,
  432. DepthCompareOp = DepthCompareOp,
  433. DepthBoundsTestEnable = DepthBoundsTestEnable,
  434. StencilTestEnable = StencilTestEnable,
  435. Front = stencilFront,
  436. Back = stencilBack,
  437. MinDepthBounds = MinDepthBounds,
  438. MaxDepthBounds = MaxDepthBounds
  439. };
  440. var colorBlendState = new PipelineColorBlendStateCreateInfo()
  441. {
  442. SType = StructureType.PipelineColorBlendStateCreateInfo,
  443. LogicOpEnable = LogicOpEnable,
  444. LogicOp = LogicOp,
  445. AttachmentCount = ColorBlendAttachmentStateCount,
  446. PAttachments = pColorBlendAttachmentState
  447. };
  448. PipelineColorBlendAdvancedStateCreateInfoEXT colorBlendAdvancedState;
  449. if (!AdvancedBlendSrcPreMultiplied ||
  450. !AdvancedBlendDstPreMultiplied ||
  451. AdvancedBlendOverlap != BlendOverlapEXT.UncorrelatedExt)
  452. {
  453. colorBlendAdvancedState = new PipelineColorBlendAdvancedStateCreateInfoEXT()
  454. {
  455. SType = StructureType.PipelineColorBlendAdvancedStateCreateInfoExt,
  456. SrcPremultiplied = AdvancedBlendSrcPreMultiplied,
  457. DstPremultiplied = AdvancedBlendDstPreMultiplied,
  458. BlendOverlap = AdvancedBlendOverlap
  459. };
  460. colorBlendState.PNext = &colorBlendAdvancedState;
  461. }
  462. bool supportsExtDynamicState = gd.Capabilities.SupportsExtendedDynamicState;
  463. int dynamicStatesCount = supportsExtDynamicState ? 9 : 8;
  464. DynamicState* dynamicStates = stackalloc DynamicState[dynamicStatesCount];
  465. dynamicStates[0] = DynamicState.Viewport;
  466. dynamicStates[1] = DynamicState.Scissor;
  467. dynamicStates[2] = DynamicState.DepthBias;
  468. dynamicStates[3] = DynamicState.DepthBounds;
  469. dynamicStates[4] = DynamicState.StencilCompareMask;
  470. dynamicStates[5] = DynamicState.StencilWriteMask;
  471. dynamicStates[6] = DynamicState.StencilReference;
  472. dynamicStates[7] = DynamicState.BlendConstants;
  473. if (supportsExtDynamicState)
  474. {
  475. dynamicStates[8] = DynamicState.VertexInputBindingStrideExt;
  476. }
  477. var pipelineDynamicStateCreateInfo = new PipelineDynamicStateCreateInfo()
  478. {
  479. SType = StructureType.PipelineDynamicStateCreateInfo,
  480. DynamicStateCount = (uint)dynamicStatesCount,
  481. PDynamicStates = dynamicStates
  482. };
  483. if (gd.Capabilities.SupportsSubgroupSizeControl)
  484. {
  485. UpdateStageRequiredSubgroupSizes(gd, (int)StagesCount);
  486. }
  487. var pipelineCreateInfo = new GraphicsPipelineCreateInfo()
  488. {
  489. SType = StructureType.GraphicsPipelineCreateInfo,
  490. StageCount = StagesCount,
  491. PStages = Stages.Pointer,
  492. PVertexInputState = &vertexInputState,
  493. PInputAssemblyState = &inputAssemblyState,
  494. PTessellationState = &tessellationState,
  495. PViewportState = &viewportState,
  496. PRasterizationState = &rasterizationState,
  497. PMultisampleState = &multisampleState,
  498. PDepthStencilState = &depthStencilState,
  499. PColorBlendState = &colorBlendState,
  500. PDynamicState = &pipelineDynamicStateCreateInfo,
  501. Layout = PipelineLayout,
  502. RenderPass = renderPass,
  503. BasePipelineIndex = -1
  504. };
  505. gd.Api.CreateGraphicsPipelines(device, cache, 1, &pipelineCreateInfo, null, &pipelineHandle).ThrowOnError();
  506. }
  507. pipeline = new Auto<DisposablePipeline>(new DisposablePipeline(gd.Api, device, pipelineHandle));
  508. program.AddGraphicsPipeline(ref Internal, pipeline);
  509. return pipeline;
  510. }
  511. private unsafe void UpdateStageRequiredSubgroupSizes(VulkanRenderer gd, int count)
  512. {
  513. for (int index = 0; index < count; index++)
  514. {
  515. bool canUseExplicitSubgroupSize =
  516. (gd.Capabilities.RequiredSubgroupSizeStages & Stages[index].Stage) != 0 &&
  517. gd.Capabilities.MinSubgroupSize <= RequiredSubgroupSize &&
  518. gd.Capabilities.MaxSubgroupSize >= RequiredSubgroupSize;
  519. Stages[index].PNext = canUseExplicitSubgroupSize ? StageRequiredSubgroupSizes.Pointer + index : null;
  520. }
  521. }
  522. private void UpdateVertexAttributeDescriptions()
  523. {
  524. // Vertex attributes exceeding the stride are invalid.
  525. // In metal, they cause glitches with the vertex shader fetching incorrect values.
  526. // To work around this, we reduce the format to something that doesn't exceed the stride if possible.
  527. // The assumption is that the exceeding components are not actually accessed on the shader.
  528. for (int index = 0; index < VertexAttributeDescriptionsCount; index++)
  529. {
  530. var attribute = Internal.VertexAttributeDescriptions[index];
  531. ref var vb = ref Internal.VertexBindingDescriptions[(int)attribute.Binding];
  532. Format format = attribute.Format;
  533. while (vb.Stride != 0 && attribute.Offset + FormatTable.GetAttributeFormatSize(format) > vb.Stride)
  534. {
  535. Format newFormat = FormatTable.DropLastComponent(format);
  536. if (newFormat == format)
  537. {
  538. // That case means we failed to find a format that fits within the stride,
  539. // so just restore the original format and give up.
  540. format = attribute.Format;
  541. break;
  542. }
  543. format = newFormat;
  544. }
  545. attribute.Format = format;
  546. _vertexAttributeDescriptions2[index] = attribute;
  547. }
  548. }
  549. public void Dispose()
  550. {
  551. Stages.Dispose();
  552. StageRequiredSubgroupSizes.Dispose();
  553. }
  554. }
  555. }