Memory changes 3

General memory improvements to decrease GC pressure and frequency.

Pool big arrays and objects that are created and deleted often.

Skip data copies when they aren't needed.

Inline flag checks to skip unneeded allocations.

From my testing the performance is about the same, but the GC frequency is much lower and collection is faster causing less and smaller spikes.
This commit is contained in:
LotP
2025-11-23 13:43:14 -06:00
committed by KeatonTheBot
parent c1e24961f9
commit 35bced8527
42 changed files with 703 additions and 331 deletions
+182 -33
View File
@@ -1,7 +1,9 @@
using Ryujinx.Graphics.GAL;
using Silk.NET.Vulkan;
using System;
using System.Collections.Generic;
using System.Linq;
using Format = Ryujinx.Graphics.GAL.Format;
using VkFormat = Silk.NET.Vulkan.Format;
namespace Ryujinx.Graphics.Vulkan
@@ -9,26 +11,27 @@ namespace Ryujinx.Graphics.Vulkan
class FramebufferParams
{
private readonly Device _device;
private readonly Auto<DisposableImageView>[] _attachments;
private readonly TextureView[] _colors;
private readonly TextureView _depthStencil;
private readonly TextureView[] _colorsCanonical;
private readonly TextureView _baseAttachment;
private readonly uint _validColorAttachments;
private Auto<DisposableImageView>[] _attachments;
private TextureView[] _colors;
private TextureView _depthStencil;
private TextureView[] _colorsCanonical;
private TextureView _baseAttachment;
private uint _validColorAttachments;
private int _totalCount;
public uint Width { get; }
public uint Height { get; }
public uint Layers { get; }
public uint Width { get; private set; }
public uint Height { get; private set; }
public uint Layers { get; private set; }
public uint[] AttachmentSamples { get; }
public VkFormat[] AttachmentFormats { get; }
public int[] AttachmentIndices { get; }
public uint AttachmentIntegerFormatMask { get; }
public bool LogicOpsAllowed { get; }
public uint[] AttachmentSamples { get; private set; }
public VkFormat[] AttachmentFormats { get; private set; }
public int[] AttachmentIndices { get; private set; }
public uint AttachmentIntegerFormatMask { get; private set; }
public bool LogicOpsAllowed { get; private set; }
public int AttachmentsCount { get; }
public int MaxColorAttachmentIndex => AttachmentIndices.Length > 0 ? AttachmentIndices[^1] : -1;
public bool HasDepthStencil { get; }
public int AttachmentsCount { get; private set; }
public int MaxColorAttachmentIndex => ColorAttachmentsCount > 0 ? AttachmentIndices[ColorAttachmentsCount - 1] : -1;
public bool HasDepthStencil { get; private set; }
public int ColorAttachmentsCount => AttachmentsCount - (HasDepthStencil ? 1 : 0);
public FramebufferParams(Device device, TextureView view, uint width, uint height)
@@ -49,7 +52,7 @@ namespace Ryujinx.Graphics.Vulkan
else
{
_colors = [view];
_colorsCanonical = _colors;
_colorsCanonical = [view];
}
Width = width;
@@ -63,6 +66,7 @@ namespace Ryujinx.Graphics.Vulkan
LogicOpsAllowed = !format.IsFloatOrSrgb();
AttachmentsCount = 1;
_totalCount = 1;
HasDepthStencil = isDepthStencil;
}
@@ -132,7 +136,7 @@ namespace Ryujinx.Graphics.Vulkan
AttachmentIntegerFormatMask = attachmentIntegerFormatMask;
LogicOpsAllowed = !allFormatsFloatOrSrgb;
if (depthStencil is TextureView dsTexture && dsTexture.Valid)
if (depthStencil is TextureView { Valid: true } dsTexture)
{
_attachments[count - 1] = dsTexture.GetImageViewForAttachment();
_depthStencil = dsTexture;
@@ -158,11 +162,151 @@ namespace Ryujinx.Graphics.Vulkan
Layers = layers;
AttachmentsCount = count;
_totalCount = colors.Length;
}
public FramebufferParams Update(ITexture[] colors, ITexture depthStencil)
{
int colorsCount = colors.Count(IsValidTextureView);
int count = colorsCount + (IsValidTextureView(depthStencil) ? 1 : 0);
Array.Clear(_attachments);
Array.Clear(_colors);
if (_attachments.Length < count)
{
Array.Resize(ref _attachments, count);
}
if (_colors.Length < colorsCount)
{
Array.Resize(ref _colors, colorsCount);
}
if (_colorsCanonical.Length < colors.Length)
{
Array.Resize(ref _colorsCanonical, colors.Length);
}
for (int i = 0; i < colors.Length; i++)
{
ITexture color = colors[i];
if (color is TextureView { Valid: true } view)
{
_colorsCanonical[i] = view;
}
else
{
_colorsCanonical[i] = null;
}
}
Array.Clear(AttachmentSamples);
Array.Clear(AttachmentFormats);
Array.Clear(AttachmentIndices);
if (AttachmentSamples.Length < count)
{
uint[] attachmentSamples = AttachmentSamples;
Array.Resize(ref attachmentSamples, count);
AttachmentSamples = attachmentSamples;
}
if (AttachmentFormats.Length < count)
{
VkFormat[] attachmentFormats = AttachmentFormats;
Array.Resize(ref attachmentFormats, count);
AttachmentFormats = attachmentFormats;
}
if (AttachmentIndices.Length < colorsCount)
{
int[] attachmentIndices = AttachmentIndices;
Array.Resize(ref attachmentIndices, colorsCount);
AttachmentIndices = attachmentIndices;
}
uint width = uint.MaxValue;
uint height = uint.MaxValue;
uint layers = uint.MaxValue;
int index = 0;
uint attachmentIntegerFormatMask = 0;
bool allFormatsFloatOrSrgb = colorsCount != 0;
_validColorAttachments = 0;
_baseAttachment = null;
for (int bindIndex = 0; bindIndex < colors.Length; bindIndex++)
{
TextureView texture = _colorsCanonical[bindIndex];
if (texture is not null)
{
_attachments[index] = texture.GetImageViewForAttachment();
_colors[index] = texture;
_validColorAttachments |= 1u << bindIndex;
_baseAttachment = texture;
AttachmentSamples[index] = (uint)texture.Info.Samples;
AttachmentFormats[index] = texture.VkFormat;
AttachmentIndices[index] = bindIndex;
Format format = texture.Info.Format;
if (format.IsInteger())
{
attachmentIntegerFormatMask |= 1u << bindIndex;
}
allFormatsFloatOrSrgb &= format.IsFloatOrSrgb();
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;
}
}
}
AttachmentIntegerFormatMask = attachmentIntegerFormatMask;
LogicOpsAllowed = !allFormatsFloatOrSrgb;
_depthStencil = null;
HasDepthStencil = false;
if (depthStencil is TextureView { Valid: true } dsTexture)
{
_attachments[count - 1] = dsTexture.GetImageViewForAttachment();
_depthStencil = dsTexture;
_baseAttachment ??= 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;
_totalCount = colors.Length;
return this;
}
public Auto<DisposableImageView> GetAttachment(int index)
{
if ((uint)index >= _attachments.Length)
if ((uint)index >= AttachmentsCount)
{
return null;
}
@@ -182,7 +326,7 @@ namespace Ryujinx.Graphics.Vulkan
public ComponentType GetAttachmentComponentType(int index)
{
if (_colors != null && (uint)index < _colors.Length)
if (_colors != null && (uint)index < ColorAttachmentsCount)
{
var format = _colors[index].Info.Format;
@@ -217,7 +361,7 @@ namespace Ryujinx.Graphics.Vulkan
private static bool IsValidTextureView(ITexture texture)
{
return texture is TextureView view && view.Valid;
return texture is TextureView { Valid: true };
}
public ClearRect GetClearRect(Rectangle<int> scissor, int layer, int layerCount)
@@ -232,9 +376,9 @@ namespace Ryujinx.Graphics.Vulkan
public unsafe Auto<DisposableFramebuffer> Create(Vk api, CommandBufferScoped cbs, Auto<DisposableRenderPass> renderPass)
{
ImageView* attachments = stackalloc ImageView[_attachments.Length];
ImageView* attachments = stackalloc ImageView[AttachmentsCount];
for (int i = 0; i < _attachments.Length; i++)
for (int i = 0; i < AttachmentsCount; i++)
{
attachments[i] = _attachments[i].Get(cbs).Value;
}
@@ -243,7 +387,7 @@ namespace Ryujinx.Graphics.Vulkan
{
SType = StructureType.FramebufferCreateInfo,
RenderPass = renderPass.Get(cbs).Value,
AttachmentCount = (uint)_attachments.Length,
AttachmentCount = (uint)AttachmentsCount,
PAttachments = attachments,
Width = Width,
Height = Height,
@@ -251,14 +395,13 @@ namespace Ryujinx.Graphics.Vulkan
};
api.CreateFramebuffer(_device, in framebufferCreateInfo, null, out var framebuffer).ThrowOnError();
return new Auto<DisposableFramebuffer>(new DisposableFramebuffer(api, _device, framebuffer), null, _attachments);
return new Auto<DisposableFramebuffer>(new DisposableFramebuffer(api, _device, framebuffer), null, _attachments[..AttachmentsCount]);
}
public TextureView[] GetAttachmentViews()
{
var result = new TextureView[_attachments.Length];
_colors?.CopyTo(result, 0);
var result = new TextureView[AttachmentsCount];
_colors?.AsSpan(..ColorAttachmentsCount).CopyTo(result.AsSpan());
if (_depthStencil != null)
{
@@ -277,8 +420,11 @@ namespace Ryujinx.Graphics.Vulkan
{
if (_colors != null)
{
foreach (var color in _colors)
int count = ColorAttachmentsCount;
for (int i = 0; i < count; i++)
{
TextureView color = _colors[i];
// If Clear or DontCare were used, this would need to be write bit.
color.Storage?.QueueLoadOpBarrier(cbs, false);
}
@@ -293,8 +439,11 @@ namespace Ryujinx.Graphics.Vulkan
{
if (_colors != null)
{
foreach (var color in _colors)
int count = ColorAttachmentsCount;
for (int i = 0; i < count; i++)
{
TextureView color = _colors[i];
color.Storage?.AddStoreOpUsage(false);
}
}
@@ -306,7 +455,7 @@ namespace Ryujinx.Graphics.Vulkan
{
_depthStencil?.Storage.ClearBindings();
for (int i = 0; i < _colorsCanonical.Length; i++)
for (int i = 0; i < _totalCount; i++)
{
_colorsCanonical[i]?.Storage.ClearBindings();
}
@@ -316,7 +465,7 @@ namespace Ryujinx.Graphics.Vulkan
{
_depthStencil?.Storage.AddBinding(_depthStencil);
for (int i = 0; i < _colorsCanonical.Length; i++)
for (int i = 0; i < _totalCount; i++)
{
TextureView color = _colorsCanonical[i];
color?.Storage.AddBinding(color);