RenderPassHolder.cs
1 using Silk.NET.Vulkan; 2 using System; 3 using System.Collections.Generic; 4 using System.Linq; 5 6 namespace Ryujinx.Graphics.Vulkan 7 { 8 internal class RenderPassHolder 9 { 10 private readonly struct FramebufferCacheKey : IRefEquatable<FramebufferCacheKey> 11 { 12 private readonly uint _width; 13 private readonly uint _height; 14 private readonly uint _layers; 15 16 public FramebufferCacheKey(uint width, uint height, uint layers) 17 { 18 _width = width; 19 _height = height; 20 _layers = layers; 21 } 22 23 public override int GetHashCode() 24 { 25 return HashCode.Combine(_width, _height, _layers); 26 } 27 28 public bool Equals(ref FramebufferCacheKey other) 29 { 30 return other._width == _width && other._height == _height && other._layers == _layers; 31 } 32 } 33 34 private readonly record struct ForcedFence(TextureStorage Texture, PipelineStageFlags StageFlags); 35 36 private readonly TextureView[] _textures; 37 private readonly Auto<DisposableRenderPass> _renderPass; 38 private readonly HashTableSlim<FramebufferCacheKey, Auto<DisposableFramebuffer>> _framebuffers; 39 private readonly RenderPassCacheKey _key; 40 private readonly List<ForcedFence> _forcedFences; 41 42 public unsafe RenderPassHolder(VulkanRenderer gd, Device device, RenderPassCacheKey key, FramebufferParams fb) 43 { 44 // Create render pass using framebuffer params. 45 46 const int MaxAttachments = Constants.MaxRenderTargets + 1; 47 48 AttachmentDescription[] attachmentDescs = null; 49 50 var subpass = new SubpassDescription 51 { 52 PipelineBindPoint = PipelineBindPoint.Graphics, 53 }; 54 55 AttachmentReference* attachmentReferences = stackalloc AttachmentReference[MaxAttachments]; 56 57 var hasFramebuffer = fb != null; 58 59 if (hasFramebuffer && fb.AttachmentsCount != 0) 60 { 61 attachmentDescs = new AttachmentDescription[fb.AttachmentsCount]; 62 63 for (int i = 0; i < fb.AttachmentsCount; i++) 64 { 65 attachmentDescs[i] = new AttachmentDescription( 66 0, 67 fb.AttachmentFormats[i], 68 TextureStorage.ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, fb.AttachmentSamples[i]), 69 AttachmentLoadOp.Load, 70 AttachmentStoreOp.Store, 71 AttachmentLoadOp.Load, 72 AttachmentStoreOp.Store, 73 ImageLayout.General, 74 ImageLayout.General); 75 } 76 77 int colorAttachmentsCount = fb.ColorAttachmentsCount; 78 79 if (colorAttachmentsCount > MaxAttachments - 1) 80 { 81 colorAttachmentsCount = MaxAttachments - 1; 82 } 83 84 if (colorAttachmentsCount != 0) 85 { 86 int maxAttachmentIndex = fb.MaxColorAttachmentIndex; 87 subpass.ColorAttachmentCount = (uint)maxAttachmentIndex + 1; 88 subpass.PColorAttachments = &attachmentReferences[0]; 89 90 // Fill with VK_ATTACHMENT_UNUSED to cover any gaps. 91 for (int i = 0; i <= maxAttachmentIndex; i++) 92 { 93 subpass.PColorAttachments[i] = new AttachmentReference(Vk.AttachmentUnused, ImageLayout.Undefined); 94 } 95 96 for (int i = 0; i < colorAttachmentsCount; i++) 97 { 98 int bindIndex = fb.AttachmentIndices[i]; 99 100 subpass.PColorAttachments[bindIndex] = new AttachmentReference((uint)i, ImageLayout.General); 101 } 102 } 103 104 if (fb.HasDepthStencil) 105 { 106 uint dsIndex = (uint)fb.AttachmentsCount - 1; 107 108 subpass.PDepthStencilAttachment = &attachmentReferences[MaxAttachments - 1]; 109 *subpass.PDepthStencilAttachment = new AttachmentReference(dsIndex, ImageLayout.General); 110 } 111 } 112 113 var subpassDependency = PipelineConverter.CreateSubpassDependency(gd); 114 115 fixed (AttachmentDescription* pAttachmentDescs = attachmentDescs) 116 { 117 var renderPassCreateInfo = new RenderPassCreateInfo 118 { 119 SType = StructureType.RenderPassCreateInfo, 120 PAttachments = pAttachmentDescs, 121 AttachmentCount = attachmentDescs != null ? (uint)attachmentDescs.Length : 0, 122 PSubpasses = &subpass, 123 SubpassCount = 1, 124 PDependencies = &subpassDependency, 125 DependencyCount = 1, 126 }; 127 128 gd.Api.CreateRenderPass(device, in renderPassCreateInfo, null, out var renderPass).ThrowOnError(); 129 130 _renderPass = new Auto<DisposableRenderPass>(new DisposableRenderPass(gd.Api, device, renderPass)); 131 } 132 133 _framebuffers = new HashTableSlim<FramebufferCacheKey, Auto<DisposableFramebuffer>>(); 134 135 // Register this render pass with all render target views. 136 137 var textures = fb.GetAttachmentViews(); 138 139 foreach (var texture in textures) 140 { 141 texture.AddRenderPass(key, this); 142 } 143 144 _textures = textures; 145 _key = key; 146 147 _forcedFences = new List<ForcedFence>(); 148 } 149 150 public Auto<DisposableFramebuffer> GetFramebuffer(VulkanRenderer gd, CommandBufferScoped cbs, FramebufferParams fb) 151 { 152 var key = new FramebufferCacheKey(fb.Width, fb.Height, fb.Layers); 153 154 if (!_framebuffers.TryGetValue(ref key, out Auto<DisposableFramebuffer> result)) 155 { 156 result = fb.Create(gd.Api, cbs, _renderPass); 157 158 _framebuffers.Add(ref key, result); 159 } 160 161 return result; 162 } 163 164 public Auto<DisposableRenderPass> GetRenderPass() 165 { 166 return _renderPass; 167 } 168 169 public void AddForcedFence(TextureStorage storage, PipelineStageFlags stageFlags) 170 { 171 if (!_forcedFences.Any(fence => fence.Texture == storage)) 172 { 173 _forcedFences.Add(new ForcedFence(storage, stageFlags)); 174 } 175 } 176 177 public void InsertForcedFences(CommandBufferScoped cbs) 178 { 179 if (_forcedFences.Count > 0) 180 { 181 _forcedFences.RemoveAll((entry) => 182 { 183 if (entry.Texture.Disposed) 184 { 185 return true; 186 } 187 188 entry.Texture.QueueWriteToReadBarrier(cbs, AccessFlags.ShaderReadBit, entry.StageFlags); 189 190 return false; 191 }); 192 } 193 } 194 195 public bool ContainsAttachment(TextureStorage storage) 196 { 197 return _textures.Any(view => view.Storage == storage); 198 } 199 200 public void Dispose() 201 { 202 // Dispose all framebuffers. 203 204 foreach (var fb in _framebuffers.Values) 205 { 206 fb.Dispose(); 207 } 208 209 // Notify all texture views that this render pass has been disposed. 210 211 foreach (var texture in _textures) 212 { 213 texture.RemoveRenderPass(_key); 214 } 215 216 // Dispose render pass. 217 218 _renderPass.Dispose(); 219 } 220 } 221 }