aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Vulkan/RenderPassHolder.cs
diff options
context:
space:
mode:
authorriperiperi <rhy3756547@hotmail.com>2024-01-31 22:49:50 +0000
committerGitHub <noreply@github.com>2024-01-31 23:49:50 +0100
commitc94f0fbb8307873f68df982c100d3fb01aa6ccf5 (patch)
tree327a039f016b3e0ae45713e0f5dd413a04d673ae /src/Ryujinx.Graphics.Vulkan/RenderPassHolder.cs
parentd1b30fbe08d79ad81167358779d77cf4e7167386 (diff)
Vulkan: Add Render Pass / Framebuffer Cache (#6182)
* Vulkan: Add Render Pass / Framebuffer Cache Cache is owned by each texture view. - Window's way of getting framebuffer cache for swapchain images is really messy - it creates a TextureView out of just a vk image view, with invalid info and no storage. * Clear up limited use of alternate TextureView constructor * Formatting and messages * More formatting and messages I apologize for `_colorsCanonical[index]?.Storage?.InsertReadToWriteBarrier`, the compiler made me do it * Self review, change GetFramebuffer to GetPassAndFramebuffer * Avoid allocations on Remove for HashTableSlim * Member can be readonly * Generate texture create info for swapchain images * Improve hashcode * Remove format, samples, size and isDepthStencil when possible Tested in a number of games, seems fine. * Removed load op barriers These can be introduced later. * Reintroduce UpdateModifications Technically meant to be replaced by load op stuff.
Diffstat (limited to 'src/Ryujinx.Graphics.Vulkan/RenderPassHolder.cs')
-rw-r--r--src/Ryujinx.Graphics.Vulkan/RenderPassHolder.cs180
1 files changed, 180 insertions, 0 deletions
diff --git a/src/Ryujinx.Graphics.Vulkan/RenderPassHolder.cs b/src/Ryujinx.Graphics.Vulkan/RenderPassHolder.cs
new file mode 100644
index 00000000..3d883b2d
--- /dev/null
+++ b/src/Ryujinx.Graphics.Vulkan/RenderPassHolder.cs
@@ -0,0 +1,180 @@
+using Silk.NET.Vulkan;
+using System;
+
+namespace Ryujinx.Graphics.Vulkan
+{
+ internal class RenderPassHolder
+ {
+ private readonly struct FramebufferCacheKey : IRefEquatable<FramebufferCacheKey>
+ {
+ private readonly uint _width;
+ private readonly uint _height;
+ private readonly uint _layers;
+
+ public FramebufferCacheKey(uint width, uint height, uint layers)
+ {
+ _width = width;
+ _height = height;
+ _layers = layers;
+ }
+
+ public override int GetHashCode()
+ {
+ return HashCode.Combine(_width, _height, _layers);
+ }
+
+ public bool Equals(ref FramebufferCacheKey other)
+ {
+ return other._width == _width && other._height == _height && other._layers == _layers;
+ }
+ }
+
+ private readonly TextureView[] _textures;
+ private readonly Auto<DisposableRenderPass> _renderPass;
+ private readonly HashTableSlim<FramebufferCacheKey, Auto<DisposableFramebuffer>> _framebuffers;
+ private readonly RenderPassCacheKey _key;
+
+ public unsafe RenderPassHolder(VulkanRenderer gd, Device device, RenderPassCacheKey key, FramebufferParams fb)
+ {
+ // Create render pass using framebuffer params.
+
+ const int MaxAttachments = Constants.MaxRenderTargets + 1;
+
+ AttachmentDescription[] attachmentDescs = null;
+
+ var subpass = new SubpassDescription
+ {
+ PipelineBindPoint = PipelineBindPoint.Graphics,
+ };
+
+ AttachmentReference* attachmentReferences = stackalloc AttachmentReference[MaxAttachments];
+
+ var hasFramebuffer = fb != null;
+
+ if (hasFramebuffer && fb.AttachmentsCount != 0)
+ {
+ attachmentDescs = new AttachmentDescription[fb.AttachmentsCount];
+
+ for (int i = 0; i < fb.AttachmentsCount; i++)
+ {
+ attachmentDescs[i] = new AttachmentDescription(
+ 0,
+ fb.AttachmentFormats[i],
+ TextureStorage.ConvertToSampleCountFlags(gd.Capabilities.SupportedSampleCounts, fb.AttachmentSamples[i]),
+ AttachmentLoadOp.Load,
+ AttachmentStoreOp.Store,
+ AttachmentLoadOp.Load,
+ AttachmentStoreOp.Store,
+ ImageLayout.General,
+ ImageLayout.General);
+ }
+
+ int colorAttachmentsCount = fb.ColorAttachmentsCount;
+
+ if (colorAttachmentsCount > MaxAttachments - 1)
+ {
+ colorAttachmentsCount = MaxAttachments - 1;
+ }
+
+ if (colorAttachmentsCount != 0)
+ {
+ int maxAttachmentIndex = fb.MaxColorAttachmentIndex;
+ subpass.ColorAttachmentCount = (uint)maxAttachmentIndex + 1;
+ subpass.PColorAttachments = &attachmentReferences[0];
+
+ // Fill with VK_ATTACHMENT_UNUSED to cover any gaps.
+ for (int i = 0; i <= maxAttachmentIndex; i++)
+ {
+ subpass.PColorAttachments[i] = new AttachmentReference(Vk.AttachmentUnused, ImageLayout.Undefined);
+ }
+
+ for (int i = 0; i < colorAttachmentsCount; i++)
+ {
+ int bindIndex = fb.AttachmentIndices[i];
+
+ subpass.PColorAttachments[bindIndex] = new AttachmentReference((uint)i, ImageLayout.General);
+ }
+ }
+
+ if (fb.HasDepthStencil)
+ {
+ uint dsIndex = (uint)fb.AttachmentsCount - 1;
+
+ subpass.PDepthStencilAttachment = &attachmentReferences[MaxAttachments - 1];
+ *subpass.PDepthStencilAttachment = new AttachmentReference(dsIndex, ImageLayout.General);
+ }
+ }
+
+ var subpassDependency = PipelineConverter.CreateSubpassDependency();
+
+ fixed (AttachmentDescription* pAttachmentDescs = attachmentDescs)
+ {
+ var renderPassCreateInfo = new RenderPassCreateInfo
+ {
+ SType = StructureType.RenderPassCreateInfo,
+ PAttachments = pAttachmentDescs,
+ AttachmentCount = attachmentDescs != null ? (uint)attachmentDescs.Length : 0,
+ PSubpasses = &subpass,
+ SubpassCount = 1,
+ PDependencies = &subpassDependency,
+ DependencyCount = 1,
+ };
+
+ gd.Api.CreateRenderPass(device, renderPassCreateInfo, null, out var renderPass).ThrowOnError();
+
+ _renderPass?.Dispose();
+ _renderPass = new Auto<DisposableRenderPass>(new DisposableRenderPass(gd.Api, device, renderPass));
+ }
+
+ _framebuffers = new HashTableSlim<FramebufferCacheKey, Auto<DisposableFramebuffer>>();
+
+ // Register this render pass with all render target views.
+
+ var textures = fb.GetAttachmentViews();
+
+ foreach (var texture in textures)
+ {
+ texture.AddRenderPass(key, this);
+ }
+
+ _textures = textures;
+ _key = key;
+ }
+
+ public Auto<DisposableFramebuffer> GetFramebuffer(VulkanRenderer gd, CommandBufferScoped cbs, FramebufferParams fb)
+ {
+ var key = new FramebufferCacheKey(fb.Width, fb.Height, fb.Layers);
+
+ if (!_framebuffers.TryGetValue(ref key, out Auto<DisposableFramebuffer> result))
+ {
+ result = fb.Create(gd.Api, cbs, _renderPass);
+
+ _framebuffers.Add(ref key, result);
+ }
+
+ return result;
+ }
+
+ public Auto<DisposableRenderPass> GetRenderPass()
+ {
+ return _renderPass;
+ }
+
+ public void Dispose()
+ {
+ // Dispose all framebuffers
+
+ foreach (var fb in _framebuffers.Values)
+ {
+ fb.Dispose();
+ }
+
+ // Notify all texture views that this render pass has been disposed.
+
+ foreach (var texture in _textures)
+ {
+ texture.RemoveRenderPass(_key);
+ }
+ }
+ }
+}