diff options
Diffstat (limited to 'Ryujinx.Graphics.Vulkan/FramebufferParams.cs')
-rw-r--r-- | Ryujinx.Graphics.Vulkan/FramebufferParams.cs | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/Ryujinx.Graphics.Vulkan/FramebufferParams.cs b/Ryujinx.Graphics.Vulkan/FramebufferParams.cs new file mode 100644 index 00000000..e5318e93 --- /dev/null +++ b/Ryujinx.Graphics.Vulkan/FramebufferParams.cs @@ -0,0 +1,203 @@ +using Ryujinx.Graphics.GAL; +using Silk.NET.Vulkan; +using System; +using System.Linq; +using VkFormat = Silk.NET.Vulkan.Format; + +namespace Ryujinx.Graphics.Vulkan +{ + class FramebufferParams + { + private readonly Device _device; + private readonly Auto<DisposableImageView>[] _attachments; + private readonly TextureView[] _colors; + private readonly TextureView _depthStencil; + private uint _validColorAttachments; + + public uint Width { get; } + public uint Height { get; } + public uint Layers { get; } + + public uint[] AttachmentSamples { get; } + public VkFormat[] AttachmentFormats { get; } + public int[] AttachmentIndices { get; } + + public int AttachmentsCount { get; } + public int MaxColorAttachmentIndex { get; } + public bool HasDepthStencil { get; } + public int ColorAttachmentsCount => AttachmentsCount - (HasDepthStencil ? 1 : 0); + + public FramebufferParams( + Device device, + Auto<DisposableImageView> view, + uint width, + uint height, + bool isDepthStencil, + VkFormat format) + { + _device = device; + _attachments = new[] { view }; + _validColorAttachments = 1u; + + Width = width; + Height = height; + Layers = 1; + + AttachmentSamples = new[] { 1u }; + AttachmentFormats = new[] { format }; + AttachmentIndices = new[] { 0 }; + + AttachmentsCount = 1; + + HasDepthStencil = isDepthStencil; + } + + public FramebufferParams(Device device, ITexture[] colors, ITexture depthStencil) + { + _device = device; + + int colorsCount = colors.Count(IsValidTextureView); + + int count = colorsCount + (IsValidTextureView(depthStencil) ? 1 : 0); + + _attachments = new Auto<DisposableImageView>[count]; + _colors = new TextureView[colorsCount]; + + AttachmentSamples = new uint[count]; + AttachmentFormats = new VkFormat[count]; + AttachmentIndices = new int[count]; + MaxColorAttachmentIndex = colors.Length - 1; + + uint width = uint.MaxValue; + uint height = uint.MaxValue; + uint layers = uint.MaxValue; + + int index = 0; + int bindIndex = 0; + + foreach (ITexture color in colors) + { + if (IsValidTextureView(color)) + { + var texture = (TextureView)color; + + _attachments[index] = texture.GetImageViewForAttachment(); + _colors[index] = texture; + _validColorAttachments |= 1u << bindIndex; + + AttachmentSamples[index] = (uint)texture.Info.Samples; + AttachmentFormats[index] = texture.VkFormat; + AttachmentIndices[index] = bindIndex; + + width = Math.Min(width, (uint)texture.Width); + height = Math.Min(height, (uint)texture.Height); + layers = Math.Min(layers, (uint)texture.Layers); + + if (++index >= colorsCount) + { + break; + } + } + + bindIndex++; + } + + if (depthStencil is TextureView dsTexture && dsTexture.Valid) + { + _attachments[count - 1] = dsTexture.GetImageViewForAttachment(); + _depthStencil = dsTexture; + + AttachmentSamples[count - 1] = (uint)dsTexture.Info.Samples; + AttachmentFormats[count - 1] = dsTexture.VkFormat; + + width = Math.Min(width, (uint)dsTexture.Width); + height = Math.Min(height, (uint)dsTexture.Height); + layers = Math.Min(layers, (uint)dsTexture.Layers); + + HasDepthStencil = true; + } + + if (count == 0) + { + width = height = layers = 1; + } + + Width = width; + Height = height; + Layers = layers; + + AttachmentsCount = count; + } + + public Auto<DisposableImageView> GetAttachment(int index) + { + if ((uint)index >= _attachments.Length) + { + return null; + } + + return _attachments[index]; + } + + public bool IsValidColorAttachment(int bindIndex) + { + return (uint)bindIndex < Constants.MaxRenderTargets && (_validColorAttachments & (1u << bindIndex)) != 0; + } + + private static bool IsValidTextureView(ITexture texture) + { + return texture is TextureView view && view.Valid; + } + + public ClearRect GetClearRect(Rectangle<int> scissor, int layer) + { + int x = scissor.X; + int y = scissor.Y; + int width = Math.Min((int)Width - scissor.X, scissor.Width); + int height = Math.Min((int)Height - scissor.Y, scissor.Height); + + return new ClearRect(new Rect2D(new Offset2D(x, y), new Extent2D((uint)width, (uint)height)), (uint)layer, 1); + } + + public unsafe Auto<DisposableFramebuffer> Create(Vk api, CommandBufferScoped cbs, Auto<DisposableRenderPass> renderPass) + { + ImageView* attachments = stackalloc ImageView[_attachments.Length]; + + for (int i = 0; i < _attachments.Length; i++) + { + attachments[i] = _attachments[i].Get(cbs).Value; + } + + var framebufferCreateInfo = new FramebufferCreateInfo() + { + SType = StructureType.FramebufferCreateInfo, + RenderPass = renderPass.Get(cbs).Value, + AttachmentCount = (uint)_attachments.Length, + PAttachments = attachments, + Width = Width, + Height = Height, + Layers = Layers + }; + + api.CreateFramebuffer(_device, framebufferCreateInfo, null, out var framebuffer).ThrowOnError(); + return new Auto<DisposableFramebuffer>(new DisposableFramebuffer(api, _device, framebuffer), null, _attachments); + } + + public void UpdateModifications() + { + if (_colors != null) + { + for (int index = 0; index < _colors.Length; index++) + { + _colors[index].Storage.SetModification( + AccessFlags.AccessColorAttachmentWriteBit, + PipelineStageFlags.PipelineStageColorAttachmentOutputBit); + } + } + + _depthStencil?.Storage.SetModification( + AccessFlags.AccessDepthStencilAttachmentWriteBit, + PipelineStageFlags.PipelineStageColorAttachmentOutputBit); + } + } +} |