FramebufferParams.cs
1 using Ryujinx.Graphics.GAL; 2 using Silk.NET.Vulkan; 3 using System; 4 using System.Linq; 5 using VkFormat = Silk.NET.Vulkan.Format; 6 7 namespace Ryujinx.Graphics.Vulkan 8 { 9 class FramebufferParams 10 { 11 private readonly Device _device; 12 private readonly Auto<DisposableImageView>[] _attachments; 13 private readonly TextureView[] _colors; 14 private readonly TextureView _depthStencil; 15 private readonly TextureView[] _colorsCanonical; 16 private readonly TextureView _baseAttachment; 17 private readonly uint _validColorAttachments; 18 19 public uint Width { get; } 20 public uint Height { get; } 21 public uint Layers { get; } 22 23 public uint[] AttachmentSamples { get; } 24 public VkFormat[] AttachmentFormats { get; } 25 public int[] AttachmentIndices { get; } 26 public uint AttachmentIntegerFormatMask { get; } 27 public bool LogicOpsAllowed { get; } 28 29 public int AttachmentsCount { get; } 30 public int MaxColorAttachmentIndex => AttachmentIndices.Length > 0 ? AttachmentIndices[^1] : -1; 31 public bool HasDepthStencil { get; } 32 public int ColorAttachmentsCount => AttachmentsCount - (HasDepthStencil ? 1 : 0); 33 34 public FramebufferParams(Device device, TextureView view, uint width, uint height) 35 { 36 var format = view.Info.Format; 37 38 bool isDepthStencil = format.IsDepthOrStencil(); 39 40 _device = device; 41 _attachments = new[] { view.GetImageViewForAttachment() }; 42 _validColorAttachments = isDepthStencil ? 0u : 1u; 43 _baseAttachment = view; 44 45 if (isDepthStencil) 46 { 47 _depthStencil = view; 48 } 49 else 50 { 51 _colors = new TextureView[] { view }; 52 _colorsCanonical = _colors; 53 } 54 55 Width = width; 56 Height = height; 57 Layers = 1; 58 59 AttachmentSamples = new[] { (uint)view.Info.Samples }; 60 AttachmentFormats = new[] { view.VkFormat }; 61 AttachmentIndices = isDepthStencil ? Array.Empty<int>() : new[] { 0 }; 62 AttachmentIntegerFormatMask = format.IsInteger() ? 1u : 0u; 63 LogicOpsAllowed = !format.IsFloatOrSrgb(); 64 65 AttachmentsCount = 1; 66 67 HasDepthStencil = isDepthStencil; 68 } 69 70 public FramebufferParams(Device device, ITexture[] colors, ITexture depthStencil) 71 { 72 _device = device; 73 74 int colorsCount = colors.Count(IsValidTextureView); 75 76 int count = colorsCount + (IsValidTextureView(depthStencil) ? 1 : 0); 77 78 _attachments = new Auto<DisposableImageView>[count]; 79 _colors = new TextureView[colorsCount]; 80 _colorsCanonical = colors.Select(color => color is TextureView view && view.Valid ? view : null).ToArray(); 81 82 AttachmentSamples = new uint[count]; 83 AttachmentFormats = new VkFormat[count]; 84 AttachmentIndices = new int[colorsCount]; 85 86 uint width = uint.MaxValue; 87 uint height = uint.MaxValue; 88 uint layers = uint.MaxValue; 89 90 int index = 0; 91 int bindIndex = 0; 92 uint attachmentIntegerFormatMask = 0; 93 bool allFormatsFloatOrSrgb = colorsCount != 0; 94 95 foreach (ITexture color in colors) 96 { 97 if (IsValidTextureView(color)) 98 { 99 var texture = (TextureView)color; 100 101 _attachments[index] = texture.GetImageViewForAttachment(); 102 _colors[index] = texture; 103 _validColorAttachments |= 1u << bindIndex; 104 _baseAttachment = texture; 105 106 AttachmentSamples[index] = (uint)texture.Info.Samples; 107 AttachmentFormats[index] = texture.VkFormat; 108 AttachmentIndices[index] = bindIndex; 109 110 var format = texture.Info.Format; 111 112 if (format.IsInteger()) 113 { 114 attachmentIntegerFormatMask |= 1u << bindIndex; 115 } 116 117 allFormatsFloatOrSrgb &= format.IsFloatOrSrgb(); 118 119 width = Math.Min(width, (uint)texture.Width); 120 height = Math.Min(height, (uint)texture.Height); 121 layers = Math.Min(layers, (uint)texture.Layers); 122 123 if (++index >= colorsCount) 124 { 125 break; 126 } 127 } 128 129 bindIndex++; 130 } 131 132 AttachmentIntegerFormatMask = attachmentIntegerFormatMask; 133 LogicOpsAllowed = !allFormatsFloatOrSrgb; 134 135 if (depthStencil is TextureView dsTexture && dsTexture.Valid) 136 { 137 _attachments[count - 1] = dsTexture.GetImageViewForAttachment(); 138 _depthStencil = dsTexture; 139 _baseAttachment ??= dsTexture; 140 141 AttachmentSamples[count - 1] = (uint)dsTexture.Info.Samples; 142 AttachmentFormats[count - 1] = dsTexture.VkFormat; 143 144 width = Math.Min(width, (uint)dsTexture.Width); 145 height = Math.Min(height, (uint)dsTexture.Height); 146 layers = Math.Min(layers, (uint)dsTexture.Layers); 147 148 HasDepthStencil = true; 149 } 150 151 if (count == 0) 152 { 153 width = height = layers = 1; 154 } 155 156 Width = width; 157 Height = height; 158 Layers = layers; 159 160 AttachmentsCount = count; 161 } 162 163 public Auto<DisposableImageView> GetAttachment(int index) 164 { 165 if ((uint)index >= _attachments.Length) 166 { 167 return null; 168 } 169 170 return _attachments[index]; 171 } 172 173 public Auto<DisposableImageView> GetDepthStencilAttachment() 174 { 175 if (!HasDepthStencil) 176 { 177 return null; 178 } 179 180 return _attachments[AttachmentsCount - 1]; 181 } 182 183 public ComponentType GetAttachmentComponentType(int index) 184 { 185 if (_colors != null && (uint)index < _colors.Length) 186 { 187 var format = _colors[index].Info.Format; 188 189 if (format.IsSint()) 190 { 191 return ComponentType.SignedInteger; 192 } 193 194 if (format.IsUint()) 195 { 196 return ComponentType.UnsignedInteger; 197 } 198 } 199 200 return ComponentType.Float; 201 } 202 203 public ImageAspectFlags GetDepthStencilAspectFlags() 204 { 205 if (_depthStencil == null) 206 { 207 return ImageAspectFlags.None; 208 } 209 210 return _depthStencil.Info.Format.ConvertAspectFlags(); 211 } 212 213 public bool IsValidColorAttachment(int bindIndex) 214 { 215 return (uint)bindIndex < Constants.MaxRenderTargets && (_validColorAttachments & (1u << bindIndex)) != 0; 216 } 217 218 private static bool IsValidTextureView(ITexture texture) 219 { 220 return texture is TextureView view && view.Valid; 221 } 222 223 public ClearRect GetClearRect(Rectangle<int> scissor, int layer, int layerCount) 224 { 225 int x = scissor.X; 226 int y = scissor.Y; 227 int width = Math.Min((int)Width - scissor.X, scissor.Width); 228 int height = Math.Min((int)Height - scissor.Y, scissor.Height); 229 230 return new ClearRect(new Rect2D(new Offset2D(x, y), new Extent2D((uint)width, (uint)height)), (uint)layer, (uint)layerCount); 231 } 232 233 public unsafe Auto<DisposableFramebuffer> Create(Vk api, CommandBufferScoped cbs, Auto<DisposableRenderPass> renderPass) 234 { 235 ImageView* attachments = stackalloc ImageView[_attachments.Length]; 236 237 for (int i = 0; i < _attachments.Length; i++) 238 { 239 attachments[i] = _attachments[i].Get(cbs).Value; 240 } 241 242 var framebufferCreateInfo = new FramebufferCreateInfo 243 { 244 SType = StructureType.FramebufferCreateInfo, 245 RenderPass = renderPass.Get(cbs).Value, 246 AttachmentCount = (uint)_attachments.Length, 247 PAttachments = attachments, 248 Width = Width, 249 Height = Height, 250 Layers = Layers, 251 }; 252 253 api.CreateFramebuffer(_device, in framebufferCreateInfo, null, out var framebuffer).ThrowOnError(); 254 return new Auto<DisposableFramebuffer>(new DisposableFramebuffer(api, _device, framebuffer), null, _attachments); 255 } 256 257 public TextureView[] GetAttachmentViews() 258 { 259 var result = new TextureView[_attachments.Length]; 260 261 _colors?.CopyTo(result, 0); 262 263 if (_depthStencil != null) 264 { 265 result[^1] = _depthStencil; 266 } 267 268 return result; 269 } 270 271 public RenderPassCacheKey GetRenderPassCacheKey() 272 { 273 return new RenderPassCacheKey(_depthStencil, _colorsCanonical); 274 } 275 276 public void InsertLoadOpBarriers(VulkanRenderer gd, CommandBufferScoped cbs) 277 { 278 if (_colors != null) 279 { 280 foreach (var color in _colors) 281 { 282 // If Clear or DontCare were used, this would need to be write bit. 283 color.Storage?.QueueLoadOpBarrier(cbs, false); 284 } 285 } 286 287 _depthStencil?.Storage?.QueueLoadOpBarrier(cbs, true); 288 289 gd.Barriers.Flush(cbs, false, null, null); 290 } 291 292 public void AddStoreOpUsage() 293 { 294 if (_colors != null) 295 { 296 foreach (var color in _colors) 297 { 298 color.Storage?.AddStoreOpUsage(false); 299 } 300 } 301 302 _depthStencil?.Storage?.AddStoreOpUsage(true); 303 } 304 305 public void ClearBindings() 306 { 307 _depthStencil?.Storage.ClearBindings(); 308 309 for (int i = 0; i < _colorsCanonical.Length; i++) 310 { 311 _colorsCanonical[i]?.Storage.ClearBindings(); 312 } 313 } 314 315 public void AddBindings() 316 { 317 _depthStencil?.Storage.AddBinding(_depthStencil); 318 319 for (int i = 0; i < _colorsCanonical.Length; i++) 320 { 321 TextureView color = _colorsCanonical[i]; 322 color?.Storage.AddBinding(color); 323 } 324 } 325 326 public (RenderPassHolder rpHolder, Auto<DisposableFramebuffer> framebuffer) GetPassAndFramebuffer( 327 VulkanRenderer gd, 328 Device device, 329 CommandBufferScoped cbs) 330 { 331 return _baseAttachment.GetPassAndFramebuffer(gd, device, cbs, this); 332 } 333 334 public TextureView GetColorView(int index) 335 { 336 return _colorsCanonical[index]; 337 } 338 339 public TextureView GetDepthStencilView() 340 { 341 return _depthStencil; 342 } 343 } 344 }