RenderPassHolder.cs 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. using Silk.NET.Vulkan;
  2. using System;
  3. namespace Ryujinx.Graphics.Vulkan
  4. {
  5. internal class RenderPassHolder
  6. {
  7. private readonly struct FramebufferCacheKey : IRefEquatable<FramebufferCacheKey>
  8. {
  9. private readonly uint _width;
  10. private readonly uint _height;
  11. private readonly uint _layers;
  12. public FramebufferCacheKey(uint width, uint height, uint layers)
  13. {
  14. _width = width;
  15. _height = height;
  16. _layers = layers;
  17. }
  18. public override int GetHashCode()
  19. {
  20. return HashCode.Combine(_width, _height, _layers);
  21. }
  22. public bool Equals(ref FramebufferCacheKey other)
  23. {
  24. return other._width == _width && other._height == _height && other._layers == _layers;
  25. }
  26. }
  27. private readonly TextureView[] _textures;
  28. private readonly Auto<DisposableRenderPass> _renderPass;
  29. private readonly HashTableSlim<FramebufferCacheKey, Auto<DisposableFramebuffer>> _framebuffers;
  30. private readonly RenderPassCacheKey _key;
  31. public unsafe RenderPassHolder(VulkanRenderer gd, Device device, RenderPassCacheKey key, FramebufferParams fb)
  32. {
  33. // Create render pass using framebuffer params.
  34. const int MaxAttachments = Constants.MaxRenderTargets + 1;
  35. AttachmentDescription[] attachmentDescs = null;
  36. var subpass = new SubpassDescription
  37. {
  38. PipelineBindPoint = PipelineBindPoint.Graphics,
  39. };
  40. AttachmentReference* attachmentReferences = stackalloc AttachmentReference[MaxAttachments];
  41. var hasFramebuffer = fb != null;
  42. if (hasFramebuffer && fb.AttachmentsCount != 0)
  43. {
  44. attachmentDescs = new AttachmentDescription[fb.AttachmentsCount];
  45. for (int i = 0; i < fb.AttachmentsCount; i++)
  46. {
  47. attachmentDescs[i] = new AttachmentDescription(
  48. 0,
  49. fb.AttachmentFormats[i],
  50. TextureStorage.ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, fb.AttachmentSamples[i]),
  51. AttachmentLoadOp.Load,
  52. AttachmentStoreOp.Store,
  53. AttachmentLoadOp.Load,
  54. AttachmentStoreOp.Store,
  55. ImageLayout.General,
  56. ImageLayout.General);
  57. }
  58. int colorAttachmentsCount = fb.ColorAttachmentsCount;
  59. if (colorAttachmentsCount > MaxAttachments - 1)
  60. {
  61. colorAttachmentsCount = MaxAttachments - 1;
  62. }
  63. if (colorAttachmentsCount != 0)
  64. {
  65. int maxAttachmentIndex = fb.MaxColorAttachmentIndex;
  66. subpass.ColorAttachmentCount = (uint)maxAttachmentIndex + 1;
  67. subpass.PColorAttachments = &attachmentReferences[0];
  68. // Fill with VK_ATTACHMENT_UNUSED to cover any gaps.
  69. for (int i = 0; i <= maxAttachmentIndex; i++)
  70. {
  71. subpass.PColorAttachments[i] = new AttachmentReference(Vk.AttachmentUnused, ImageLayout.Undefined);
  72. }
  73. for (int i = 0; i < colorAttachmentsCount; i++)
  74. {
  75. int bindIndex = fb.AttachmentIndices[i];
  76. subpass.PColorAttachments[bindIndex] = new AttachmentReference((uint)i, ImageLayout.General);
  77. }
  78. }
  79. if (fb.HasDepthStencil)
  80. {
  81. uint dsIndex = (uint)fb.AttachmentsCount - 1;
  82. subpass.PDepthStencilAttachment = &attachmentReferences[MaxAttachments - 1];
  83. *subpass.PDepthStencilAttachment = new AttachmentReference(dsIndex, ImageLayout.General);
  84. }
  85. }
  86. var subpassDependency = PipelineConverter.CreateSubpassDependency();
  87. fixed (AttachmentDescription* pAttachmentDescs = attachmentDescs)
  88. {
  89. var renderPassCreateInfo = new RenderPassCreateInfo
  90. {
  91. SType = StructureType.RenderPassCreateInfo,
  92. PAttachments = pAttachmentDescs,
  93. AttachmentCount = attachmentDescs != null ? (uint)attachmentDescs.Length : 0,
  94. PSubpasses = &subpass,
  95. SubpassCount = 1,
  96. PDependencies = &subpassDependency,
  97. DependencyCount = 1,
  98. };
  99. gd.Api.CreateRenderPass(device, renderPassCreateInfo, null, out var renderPass).ThrowOnError();
  100. _renderPass?.Dispose();
  101. _renderPass = new Auto<DisposableRenderPass>(new DisposableRenderPass(gd.Api, device, renderPass));
  102. }
  103. _framebuffers = new HashTableSlim<FramebufferCacheKey, Auto<DisposableFramebuffer>>();
  104. // Register this render pass with all render target views.
  105. var textures = fb.GetAttachmentViews();
  106. foreach (var texture in textures)
  107. {
  108. texture.AddRenderPass(key, this);
  109. }
  110. _textures = textures;
  111. _key = key;
  112. }
  113. public Auto<DisposableFramebuffer> GetFramebuffer(VulkanRenderer gd, CommandBufferScoped cbs, FramebufferParams fb)
  114. {
  115. var key = new FramebufferCacheKey(fb.Width, fb.Height, fb.Layers);
  116. if (!_framebuffers.TryGetValue(ref key, out Auto<DisposableFramebuffer> result))
  117. {
  118. result = fb.Create(gd.Api, cbs, _renderPass);
  119. _framebuffers.Add(ref key, result);
  120. }
  121. return result;
  122. }
  123. public Auto<DisposableRenderPass> GetRenderPass()
  124. {
  125. return _renderPass;
  126. }
  127. public void Dispose()
  128. {
  129. // Dispose all framebuffers
  130. foreach (var fb in _framebuffers.Values)
  131. {
  132. fb.Dispose();
  133. }
  134. // Notify all texture views that this render pass has been disposed.
  135. foreach (var texture in _textures)
  136. {
  137. texture.RemoveRenderPass(_key);
  138. }
  139. }
  140. }
  141. }