Compare commits
5 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
4bd2ca3f0d | ||
|
e63157cc33 | ||
|
7f2fb049f5 | ||
|
4744bde0e5 | ||
|
4a835bb2b9 |
@@ -44,7 +44,7 @@
|
|||||||
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
|
<PackageVersion Include="SixLabors.ImageSharp.Drawing" Version="1.0.0-beta11" />
|
||||||
<PackageVersion Include="SPB" Version="0.0.4-build28" />
|
<PackageVersion Include="SPB" Version="0.0.4-build28" />
|
||||||
<PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
|
<PackageVersion Include="System.Drawing.Common" Version="7.0.0" />
|
||||||
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="6.31.0" />
|
<PackageVersion Include="System.IdentityModel.Tokens.Jwt" Version="7.0.0" />
|
||||||
<PackageVersion Include="System.IO.Hashing" Version="7.0.0" />
|
<PackageVersion Include="System.IO.Hashing" Version="7.0.0" />
|
||||||
<PackageVersion Include="System.Management" Version="7.0.2" />
|
<PackageVersion Include="System.Management" Version="7.0.2" />
|
||||||
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
<PackageVersion Include="UnicornEngine.Unicorn" Version="2.0.2-rc1-fb78016" />
|
||||||
|
@@ -189,7 +189,7 @@ namespace ARMeilleure.Translation
|
|||||||
{
|
{
|
||||||
if (start.CompareTo(node.End) < 0)
|
if (start.CompareTo(node.End) < 0)
|
||||||
{
|
{
|
||||||
if (overlaps.Length >= overlapCount)
|
if (overlaps.Length <= overlapCount)
|
||||||
{
|
{
|
||||||
Array.Resize(ref overlaps, overlapCount + ArrayGrowthSize);
|
Array.Resize(ref overlaps, overlapCount + ArrayGrowthSize);
|
||||||
}
|
}
|
||||||
|
@@ -265,33 +265,47 @@ namespace Ryujinx.Ava.UI.Windows
|
|||||||
|
|
||||||
private void CheckLaunchState()
|
private void CheckLaunchState()
|
||||||
{
|
{
|
||||||
if (ShowKeyErrorOnLoad)
|
|
||||||
{
|
|
||||||
ShowKeyErrorOnLoad = false;
|
|
||||||
|
|
||||||
UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys).Wait();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (OperatingSystem.IsLinux() && LinuxHelper.VmMaxMapCount < LinuxHelper.RecommendedVmMaxMapCount)
|
if (OperatingSystem.IsLinux() && LinuxHelper.VmMaxMapCount < LinuxHelper.RecommendedVmMaxMapCount)
|
||||||
{
|
{
|
||||||
Logger.Warning?.Print(LogClass.Application, $"The value of vm.max_map_count is lower than {LinuxHelper.RecommendedVmMaxMapCount}. ({LinuxHelper.VmMaxMapCount})");
|
Logger.Warning?.Print(LogClass.Application, $"The value of vm.max_map_count is lower than {LinuxHelper.RecommendedVmMaxMapCount}. ({LinuxHelper.VmMaxMapCount})");
|
||||||
|
|
||||||
if (LinuxHelper.PkExecPath is not null)
|
if (LinuxHelper.PkExecPath is not null)
|
||||||
{
|
{
|
||||||
ShowVmMaxMapCountDialog().Wait();
|
Dispatcher.UIThread.Post(async () =>
|
||||||
|
{
|
||||||
|
if (OperatingSystem.IsLinux())
|
||||||
|
{
|
||||||
|
await ShowVmMaxMapCountDialog();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ShowVmMaxMapCountWarning().Wait();
|
Dispatcher.UIThread.Post(async () =>
|
||||||
|
{
|
||||||
|
if (OperatingSystem.IsLinux())
|
||||||
|
{
|
||||||
|
await ShowVmMaxMapCountWarning();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!ShowKeyErrorOnLoad)
|
||||||
|
{
|
||||||
if (_deferLoad)
|
if (_deferLoad)
|
||||||
{
|
{
|
||||||
_deferLoad = false;
|
_deferLoad = false;
|
||||||
|
|
||||||
ViewModel.LoadApplication(_launchPath, _startFullscreen).Wait();
|
ViewModel.LoadApplication(_launchPath, _startFullscreen).Wait();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ShowKeyErrorOnLoad = false;
|
||||||
|
|
||||||
|
Dispatcher.UIThread.Post(async () => await UserErrorDialog.ShowUserErrorDialog(UserError.NoKeys));
|
||||||
|
}
|
||||||
|
|
||||||
if (ConfigurationState.Instance.CheckUpdatesOnStart.Value && Updater.CanUpdate(false))
|
if (ConfigurationState.Instance.CheckUpdatesOnStart.Value && Updater.CanUpdate(false))
|
||||||
{
|
{
|
||||||
|
@@ -192,7 +192,7 @@ namespace Ryujinx.Common.Collections
|
|||||||
{
|
{
|
||||||
if (start.CompareTo(overlap.End) < 0)
|
if (start.CompareTo(overlap.End) < 0)
|
||||||
{
|
{
|
||||||
if (overlaps.Length >= overlapCount)
|
if (overlaps.Length <= overlapCount)
|
||||||
{
|
{
|
||||||
Array.Resize(ref overlaps, overlapCount + ArrayGrowthSize);
|
Array.Resize(ref overlaps, overlapCount + ArrayGrowthSize);
|
||||||
}
|
}
|
||||||
|
@@ -696,12 +696,15 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find view compatible matches.
|
// Find view compatible matches.
|
||||||
int overlapsCount;
|
int overlapsCount = 0;
|
||||||
|
|
||||||
|
if (info.Target != Target.TextureBuffer)
|
||||||
|
{
|
||||||
lock (_textures)
|
lock (_textures)
|
||||||
{
|
{
|
||||||
overlapsCount = _textures.FindOverlaps(range.Value, ref _textureOverlaps);
|
overlapsCount = _textures.FindOverlaps(range.Value, ref _textureOverlaps);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (_overlapInfo.Length != _textureOverlaps.Length)
|
if (_overlapInfo.Length != _textureOverlaps.Length)
|
||||||
{
|
{
|
||||||
|
@@ -79,6 +79,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
private int[] _allOffsets;
|
private int[] _allOffsets;
|
||||||
private int[] _sliceSizes;
|
private int[] _sliceSizes;
|
||||||
private readonly bool _is3D;
|
private readonly bool _is3D;
|
||||||
|
private readonly bool _isBuffer;
|
||||||
private bool _hasMipViews;
|
private bool _hasMipViews;
|
||||||
private bool _hasLayerViews;
|
private bool _hasLayerViews;
|
||||||
private readonly int _layers;
|
private readonly int _layers;
|
||||||
@@ -118,6 +119,7 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
_physicalMemory = physicalMemory;
|
_physicalMemory = physicalMemory;
|
||||||
|
|
||||||
_is3D = storage.Info.Target == Target.Texture3D;
|
_is3D = storage.Info.Target == Target.Texture3D;
|
||||||
|
_isBuffer = storage.Info.Target == Target.TextureBuffer;
|
||||||
_layers = storage.Info.GetSlices();
|
_layers = storage.Info.GetSlices();
|
||||||
_levels = storage.Info.Levels;
|
_levels = storage.Info.Levels;
|
||||||
|
|
||||||
@@ -794,7 +796,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
int targetLayerHandles = _hasLayerViews ? slices : 1;
|
int targetLayerHandles = _hasLayerViews ? slices : 1;
|
||||||
int targetLevelHandles = _hasMipViews ? levels : 1;
|
int targetLevelHandles = _hasMipViews ? levels : 1;
|
||||||
|
|
||||||
if (_is3D)
|
if (_isBuffer)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (_is3D)
|
||||||
{
|
{
|
||||||
// Future mip levels come after all layers of the last mip level. Each mipmap has less layers (depth) than the last.
|
// Future mip levels come after all layers of the last mip level. Each mipmap has less layers (depth) than the last.
|
||||||
|
|
||||||
@@ -1327,7 +1333,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||||||
{
|
{
|
||||||
TextureGroupHandle[] handles;
|
TextureGroupHandle[] handles;
|
||||||
|
|
||||||
if (!(_hasMipViews || _hasLayerViews))
|
if (_isBuffer)
|
||||||
|
{
|
||||||
|
handles = Array.Empty<TextureGroupHandle>();
|
||||||
|
}
|
||||||
|
else if (!(_hasMipViews || _hasLayerViews))
|
||||||
{
|
{
|
||||||
// Single dirty region.
|
// Single dirty region.
|
||||||
var cpuRegionHandles = new RegionHandle[TextureRange.Count];
|
var cpuRegionHandles = new RegionHandle[TextureRange.Count];
|
||||||
|
@@ -27,6 +27,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
public bool InUse;
|
public bool InUse;
|
||||||
public bool InConsumption;
|
public bool InConsumption;
|
||||||
|
public int SubmissionCount;
|
||||||
public CommandBuffer CommandBuffer;
|
public CommandBuffer CommandBuffer;
|
||||||
public FenceHolder Fence;
|
public FenceHolder Fence;
|
||||||
public SemaphoreHolder Semaphore;
|
public SemaphoreHolder Semaphore;
|
||||||
@@ -193,6 +194,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return _commandBuffers[cbIndex].Fence;
|
return _commandBuffers[cbIndex].Fence;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int GetSubmissionCount(int cbIndex)
|
||||||
|
{
|
||||||
|
return _commandBuffers[cbIndex].SubmissionCount;
|
||||||
|
}
|
||||||
|
|
||||||
private int FreeConsumed(bool wait)
|
private int FreeConsumed(bool wait)
|
||||||
{
|
{
|
||||||
int freeEntry = 0;
|
int freeEntry = 0;
|
||||||
@@ -282,6 +288,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
Debug.Assert(entry.CommandBuffer.Handle == cbs.CommandBuffer.Handle);
|
Debug.Assert(entry.CommandBuffer.Handle == cbs.CommandBuffer.Handle);
|
||||||
entry.InUse = false;
|
entry.InUse = false;
|
||||||
entry.InConsumption = true;
|
entry.InConsumption = true;
|
||||||
|
entry.SubmissionCount++;
|
||||||
_inUseCount--;
|
_inUseCount--;
|
||||||
|
|
||||||
var commandBuffer = entry.CommandBuffer;
|
var commandBuffer = entry.CommandBuffer;
|
||||||
|
@@ -6,7 +6,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
class DescriptorSetManager : IDisposable
|
class DescriptorSetManager : IDisposable
|
||||||
{
|
{
|
||||||
private const uint DescriptorPoolMultiplier = 16;
|
public const uint MaxSets = 16;
|
||||||
|
|
||||||
public class DescriptorPoolHolder : IDisposable
|
public class DescriptorPoolHolder : IDisposable
|
||||||
{
|
{
|
||||||
@@ -14,36 +14,28 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
public Device Device { get; }
|
public Device Device { get; }
|
||||||
|
|
||||||
private readonly DescriptorPool _pool;
|
private readonly DescriptorPool _pool;
|
||||||
private readonly uint _capacity;
|
private int _freeDescriptors;
|
||||||
private int _totalSets;
|
private int _totalSets;
|
||||||
private int _setsInUse;
|
private int _setsInUse;
|
||||||
private bool _done;
|
private bool _done;
|
||||||
|
|
||||||
public unsafe DescriptorPoolHolder(Vk api, Device device)
|
public unsafe DescriptorPoolHolder(Vk api, Device device, ReadOnlySpan<DescriptorPoolSize> poolSizes, bool updateAfterBind)
|
||||||
{
|
{
|
||||||
Api = api;
|
Api = api;
|
||||||
Device = device;
|
Device = device;
|
||||||
|
|
||||||
var poolSizes = new[]
|
foreach (var poolSize in poolSizes)
|
||||||
{
|
{
|
||||||
new DescriptorPoolSize(DescriptorType.UniformBuffer, (1 + Constants.MaxUniformBufferBindings) * DescriptorPoolMultiplier),
|
_freeDescriptors += (int)poolSize.DescriptorCount;
|
||||||
new DescriptorPoolSize(DescriptorType.StorageBuffer, Constants.MaxStorageBufferBindings * DescriptorPoolMultiplier),
|
}
|
||||||
new DescriptorPoolSize(DescriptorType.CombinedImageSampler, Constants.MaxTextureBindings * DescriptorPoolMultiplier),
|
|
||||||
new DescriptorPoolSize(DescriptorType.StorageImage, Constants.MaxImageBindings * DescriptorPoolMultiplier),
|
|
||||||
new DescriptorPoolSize(DescriptorType.UniformTexelBuffer, Constants.MaxTextureBindings * DescriptorPoolMultiplier),
|
|
||||||
new DescriptorPoolSize(DescriptorType.StorageTexelBuffer, Constants.MaxImageBindings * DescriptorPoolMultiplier),
|
|
||||||
};
|
|
||||||
|
|
||||||
uint maxSets = (uint)poolSizes.Length * DescriptorPoolMultiplier;
|
|
||||||
|
|
||||||
_capacity = maxSets;
|
|
||||||
|
|
||||||
fixed (DescriptorPoolSize* pPoolsSize = poolSizes)
|
fixed (DescriptorPoolSize* pPoolsSize = poolSizes)
|
||||||
{
|
{
|
||||||
var descriptorPoolCreateInfo = new DescriptorPoolCreateInfo
|
var descriptorPoolCreateInfo = new DescriptorPoolCreateInfo
|
||||||
{
|
{
|
||||||
SType = StructureType.DescriptorPoolCreateInfo,
|
SType = StructureType.DescriptorPoolCreateInfo,
|
||||||
MaxSets = maxSets,
|
Flags = updateAfterBind ? DescriptorPoolCreateFlags.UpdateAfterBindBit : DescriptorPoolCreateFlags.None,
|
||||||
|
MaxSets = MaxSets,
|
||||||
PoolSizeCount = (uint)poolSizes.Length,
|
PoolSizeCount = (uint)poolSizes.Length,
|
||||||
PPoolSizes = pPoolsSize,
|
PPoolSizes = pPoolsSize,
|
||||||
};
|
};
|
||||||
@@ -52,18 +44,22 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public DescriptorSetCollection AllocateDescriptorSets(ReadOnlySpan<DescriptorSetLayout> layouts)
|
public unsafe DescriptorSetCollection AllocateDescriptorSets(ReadOnlySpan<DescriptorSetLayout> layouts, int consumedDescriptors)
|
||||||
{
|
{
|
||||||
TryAllocateDescriptorSets(layouts, isTry: false, out var dsc);
|
TryAllocateDescriptorSets(layouts, consumedDescriptors, isTry: false, out var dsc);
|
||||||
return dsc;
|
return dsc;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TryAllocateDescriptorSets(ReadOnlySpan<DescriptorSetLayout> layouts, out DescriptorSetCollection dsc)
|
public bool TryAllocateDescriptorSets(ReadOnlySpan<DescriptorSetLayout> layouts, int consumedDescriptors, out DescriptorSetCollection dsc)
|
||||||
{
|
{
|
||||||
return TryAllocateDescriptorSets(layouts, isTry: true, out dsc);
|
return TryAllocateDescriptorSets(layouts, consumedDescriptors, isTry: true, out dsc);
|
||||||
}
|
}
|
||||||
|
|
||||||
private unsafe bool TryAllocateDescriptorSets(ReadOnlySpan<DescriptorSetLayout> layouts, bool isTry, out DescriptorSetCollection dsc)
|
private unsafe bool TryAllocateDescriptorSets(
|
||||||
|
ReadOnlySpan<DescriptorSetLayout> layouts,
|
||||||
|
int consumedDescriptors,
|
||||||
|
bool isTry,
|
||||||
|
out DescriptorSetCollection dsc)
|
||||||
{
|
{
|
||||||
Debug.Assert(!_done);
|
Debug.Assert(!_done);
|
||||||
|
|
||||||
@@ -84,7 +80,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
var result = Api.AllocateDescriptorSets(Device, &descriptorSetAllocateInfo, pDescriptorSets);
|
var result = Api.AllocateDescriptorSets(Device, &descriptorSetAllocateInfo, pDescriptorSets);
|
||||||
if (isTry && result == Result.ErrorOutOfPoolMemory)
|
if (isTry && result == Result.ErrorOutOfPoolMemory)
|
||||||
{
|
{
|
||||||
_totalSets = (int)_capacity;
|
_totalSets = (int)MaxSets;
|
||||||
_done = true;
|
_done = true;
|
||||||
DestroyIfDone();
|
DestroyIfDone();
|
||||||
dsc = default;
|
dsc = default;
|
||||||
@@ -95,6 +91,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_freeDescriptors -= consumedDescriptors;
|
||||||
_totalSets += layouts.Length;
|
_totalSets += layouts.Length;
|
||||||
_setsInUse += layouts.Length;
|
_setsInUse += layouts.Length;
|
||||||
|
|
||||||
@@ -109,9 +106,15 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
DestroyIfDone();
|
DestroyIfDone();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanFit(int count)
|
public bool CanFit(int setsCount, int descriptorsCount)
|
||||||
{
|
{
|
||||||
if (_totalSets + count <= _capacity)
|
// Try to determine if an allocation with the given parameters will succeed.
|
||||||
|
// An allocation may fail if the sets count or descriptors count exceeds the available counts
|
||||||
|
// of the pool.
|
||||||
|
// Not getting that right is not fatal, it will just create a new pool and try again,
|
||||||
|
// but it is less efficient.
|
||||||
|
|
||||||
|
if (_totalSets + setsCount <= MaxSets && _freeDescriptors >= descriptorsCount)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -148,46 +151,74 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
|
|
||||||
private readonly Device _device;
|
private readonly Device _device;
|
||||||
private DescriptorPoolHolder _currentPool;
|
private readonly DescriptorPoolHolder[] _currentPools;
|
||||||
|
|
||||||
public DescriptorSetManager(Device device)
|
public DescriptorSetManager(Device device, int poolCount)
|
||||||
{
|
{
|
||||||
_device = device;
|
_device = device;
|
||||||
|
_currentPools = new DescriptorPoolHolder[poolCount];
|
||||||
}
|
}
|
||||||
|
|
||||||
public Auto<DescriptorSetCollection> AllocateDescriptorSet(Vk api, DescriptorSetLayout layout)
|
public Auto<DescriptorSetCollection> AllocateDescriptorSet(
|
||||||
|
Vk api,
|
||||||
|
DescriptorSetLayout layout,
|
||||||
|
ReadOnlySpan<DescriptorPoolSize> poolSizes,
|
||||||
|
int poolIndex,
|
||||||
|
int consumedDescriptors,
|
||||||
|
bool updateAfterBind)
|
||||||
{
|
{
|
||||||
Span<DescriptorSetLayout> layouts = stackalloc DescriptorSetLayout[1];
|
Span<DescriptorSetLayout> layouts = stackalloc DescriptorSetLayout[1];
|
||||||
layouts[0] = layout;
|
layouts[0] = layout;
|
||||||
return AllocateDescriptorSets(api, layouts);
|
return AllocateDescriptorSets(api, layouts, poolSizes, poolIndex, consumedDescriptors, updateAfterBind);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Auto<DescriptorSetCollection> AllocateDescriptorSets(Vk api, ReadOnlySpan<DescriptorSetLayout> layouts)
|
public Auto<DescriptorSetCollection> AllocateDescriptorSets(
|
||||||
|
Vk api,
|
||||||
|
ReadOnlySpan<DescriptorSetLayout> layouts,
|
||||||
|
ReadOnlySpan<DescriptorPoolSize> poolSizes,
|
||||||
|
int poolIndex,
|
||||||
|
int consumedDescriptors,
|
||||||
|
bool updateAfterBind)
|
||||||
{
|
{
|
||||||
// If we fail the first time, just create a new pool and try again.
|
// If we fail the first time, just create a new pool and try again.
|
||||||
if (!GetPool(api, layouts.Length).TryAllocateDescriptorSets(layouts, out var dsc))
|
|
||||||
|
var pool = GetPool(api, poolSizes, poolIndex, layouts.Length, consumedDescriptors, updateAfterBind);
|
||||||
|
if (!pool.TryAllocateDescriptorSets(layouts, consumedDescriptors, out var dsc))
|
||||||
{
|
{
|
||||||
dsc = GetPool(api, layouts.Length).AllocateDescriptorSets(layouts);
|
pool = GetPool(api, poolSizes, poolIndex, layouts.Length, consumedDescriptors, updateAfterBind);
|
||||||
|
dsc = pool.AllocateDescriptorSets(layouts, consumedDescriptors);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new Auto<DescriptorSetCollection>(dsc);
|
return new Auto<DescriptorSetCollection>(dsc);
|
||||||
}
|
}
|
||||||
|
|
||||||
private DescriptorPoolHolder GetPool(Vk api, int requiredCount)
|
private DescriptorPoolHolder GetPool(
|
||||||
|
Vk api,
|
||||||
|
ReadOnlySpan<DescriptorPoolSize> poolSizes,
|
||||||
|
int poolIndex,
|
||||||
|
int setsCount,
|
||||||
|
int descriptorsCount,
|
||||||
|
bool updateAfterBind)
|
||||||
{
|
{
|
||||||
if (_currentPool == null || !_currentPool.CanFit(requiredCount))
|
ref DescriptorPoolHolder currentPool = ref _currentPools[poolIndex];
|
||||||
|
|
||||||
|
if (currentPool == null || !currentPool.CanFit(setsCount, descriptorsCount))
|
||||||
{
|
{
|
||||||
_currentPool = new DescriptorPoolHolder(api, _device);
|
currentPool = new DescriptorPoolHolder(api, _device, poolSizes, updateAfterBind);
|
||||||
}
|
}
|
||||||
|
|
||||||
return _currentPool;
|
return currentPool;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
protected virtual void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (disposing)
|
if (disposing)
|
||||||
{
|
{
|
||||||
_currentPool?.Dispose();
|
for (int index = 0; index < _currentPools.Length; index++)
|
||||||
|
{
|
||||||
|
_currentPools[index]?.Dispose();
|
||||||
|
_currentPools[index] = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -59,6 +59,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private BitMapStruct<Array2<long>> _uniformMirrored;
|
private BitMapStruct<Array2<long>> _uniformMirrored;
|
||||||
private BitMapStruct<Array2<long>> _storageMirrored;
|
private BitMapStruct<Array2<long>> _storageMirrored;
|
||||||
|
|
||||||
|
private bool _updateDescriptorCacheCbIndex;
|
||||||
|
|
||||||
[Flags]
|
[Flags]
|
||||||
private enum DirtyFlags
|
private enum DirtyFlags
|
||||||
{
|
{
|
||||||
@@ -218,6 +220,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
public void SetProgram(ShaderCollection program)
|
public void SetProgram(ShaderCollection program)
|
||||||
{
|
{
|
||||||
_program = program;
|
_program = program;
|
||||||
|
_updateDescriptorCacheCbIndex = true;
|
||||||
_dirty = DirtyFlags.All;
|
_dirty = DirtyFlags.All;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -490,7 +493,13 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
var dummyBuffer = _dummyBuffer?.GetBuffer();
|
var dummyBuffer = _dummyBuffer?.GetBuffer();
|
||||||
|
|
||||||
var dsc = program.GetNewDescriptorSetCollection(_gd, cbs.CommandBufferIndex, setIndex, out var isNew).Get(cbs);
|
if (_updateDescriptorCacheCbIndex)
|
||||||
|
{
|
||||||
|
_updateDescriptorCacheCbIndex = false;
|
||||||
|
program.UpdateDescriptorCacheCommandBufferIndex(cbs.CommandBufferIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
var dsc = program.GetNewDescriptorSetCollection(setIndex, out var isNew).Get(cbs);
|
||||||
|
|
||||||
if (!program.HasMinimalLayout)
|
if (!program.HasMinimalLayout)
|
||||||
{
|
{
|
||||||
@@ -697,6 +706,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
public void SignalCommandBufferChange()
|
public void SignalCommandBufferChange()
|
||||||
{
|
{
|
||||||
|
_updateDescriptorCacheCbIndex = true;
|
||||||
_dirty = DirtyFlags.All;
|
_dirty = DirtyFlags.All;
|
||||||
|
|
||||||
_uniformSet.Clear();
|
_uniformSet.Clear();
|
||||||
|
@@ -1,6 +1,7 @@
|
|||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
@@ -13,6 +14,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
private readonly Device _device;
|
private readonly Device _device;
|
||||||
private readonly List<MemoryAllocatorBlockList> _blockLists;
|
private readonly List<MemoryAllocatorBlockList> _blockLists;
|
||||||
private readonly int _blockAlignment;
|
private readonly int _blockAlignment;
|
||||||
|
private readonly ReaderWriterLockSlim _lock;
|
||||||
|
|
||||||
public MemoryAllocator(Vk api, VulkanPhysicalDevice physicalDevice, Device device)
|
public MemoryAllocator(Vk api, VulkanPhysicalDevice physicalDevice, Device device)
|
||||||
{
|
{
|
||||||
@@ -21,6 +23,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
_device = device;
|
_device = device;
|
||||||
_blockLists = new List<MemoryAllocatorBlockList>();
|
_blockLists = new List<MemoryAllocatorBlockList>();
|
||||||
_blockAlignment = (int)Math.Min(int.MaxValue, MaxDeviceMemoryUsageEstimate / _physicalDevice.PhysicalDeviceProperties.Limits.MaxMemoryAllocationCount);
|
_blockAlignment = (int)Math.Min(int.MaxValue, MaxDeviceMemoryUsageEstimate / _physicalDevice.PhysicalDeviceProperties.Limits.MaxMemoryAllocationCount);
|
||||||
|
_lock = new(LockRecursionPolicy.NoRecursion);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MemoryAllocation AllocateDeviceMemory(
|
public MemoryAllocation AllocateDeviceMemory(
|
||||||
@@ -39,23 +42,39 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
|
|
||||||
private MemoryAllocation Allocate(int memoryTypeIndex, ulong size, ulong alignment, bool map, bool isBuffer)
|
private MemoryAllocation Allocate(int memoryTypeIndex, ulong size, ulong alignment, bool map, bool isBuffer)
|
||||||
|
{
|
||||||
|
_lock.EnterReadLock();
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
for (int i = 0; i < _blockLists.Count; i++)
|
for (int i = 0; i < _blockLists.Count; i++)
|
||||||
{
|
{
|
||||||
var bl = _blockLists[i];
|
var bl = _blockLists[i];
|
||||||
if (bl.MemoryTypeIndex == memoryTypeIndex && bl.ForBuffer == isBuffer)
|
if (bl.MemoryTypeIndex == memoryTypeIndex && bl.ForBuffer == isBuffer)
|
||||||
{
|
|
||||||
lock (bl)
|
|
||||||
{
|
{
|
||||||
return bl.Allocate(size, alignment, map);
|
return bl.Allocate(size, alignment, map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_lock.ExitReadLock();
|
||||||
|
}
|
||||||
|
|
||||||
|
_lock.EnterWriteLock();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
var newBl = new MemoryAllocatorBlockList(_api, _device, memoryTypeIndex, _blockAlignment, isBuffer);
|
var newBl = new MemoryAllocatorBlockList(_api, _device, memoryTypeIndex, _blockAlignment, isBuffer);
|
||||||
_blockLists.Add(newBl);
|
_blockLists.Add(newBl);
|
||||||
|
|
||||||
return newBl.Allocate(size, alignment, map);
|
return newBl.Allocate(size, alignment, map);
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_lock.ExitWriteLock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal int FindSuitableMemoryTypeIndex(
|
internal int FindSuitableMemoryTypeIndex(
|
||||||
uint memoryTypeBits,
|
uint memoryTypeBits,
|
||||||
|
@@ -3,6 +3,7 @@ using Silk.NET.Vulkan;
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Threading;
|
||||||
|
|
||||||
namespace Ryujinx.Graphics.Vulkan
|
namespace Ryujinx.Graphics.Vulkan
|
||||||
{
|
{
|
||||||
@@ -166,6 +167,8 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
private readonly int _blockAlignment;
|
private readonly int _blockAlignment;
|
||||||
|
|
||||||
|
private readonly ReaderWriterLockSlim _lock;
|
||||||
|
|
||||||
public MemoryAllocatorBlockList(Vk api, Device device, int memoryTypeIndex, int blockAlignment, bool forBuffer)
|
public MemoryAllocatorBlockList(Vk api, Device device, int memoryTypeIndex, int blockAlignment, bool forBuffer)
|
||||||
{
|
{
|
||||||
_blocks = new List<Block>();
|
_blocks = new List<Block>();
|
||||||
@@ -174,6 +177,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
MemoryTypeIndex = memoryTypeIndex;
|
MemoryTypeIndex = memoryTypeIndex;
|
||||||
ForBuffer = forBuffer;
|
ForBuffer = forBuffer;
|
||||||
_blockAlignment = blockAlignment;
|
_blockAlignment = blockAlignment;
|
||||||
|
_lock = new(LockRecursionPolicy.NoRecursion);
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsafe MemoryAllocation Allocate(ulong size, ulong alignment, bool map)
|
public unsafe MemoryAllocation Allocate(ulong size, ulong alignment, bool map)
|
||||||
@@ -184,6 +188,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
throw new ArgumentOutOfRangeException(nameof(alignment), $"Invalid alignment 0x{alignment:X}.");
|
throw new ArgumentOutOfRangeException(nameof(alignment), $"Invalid alignment 0x{alignment:X}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_lock.EnterReadLock();
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
for (int i = 0; i < _blocks.Count; i++)
|
for (int i = 0; i < _blocks.Count; i++)
|
||||||
{
|
{
|
||||||
var block = _blocks[i];
|
var block = _blocks[i];
|
||||||
@@ -197,6 +205,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_lock.ExitReadLock();
|
||||||
|
}
|
||||||
|
|
||||||
ulong blockAlignedSize = BitUtils.AlignUp(size, (ulong)_blockAlignment);
|
ulong blockAlignedSize = BitUtils.AlignUp(size, (ulong)_blockAlignment);
|
||||||
|
|
||||||
@@ -243,6 +256,10 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
block.Free(offset, size);
|
block.Free(offset, size);
|
||||||
|
|
||||||
if (block.IsTotallyFree())
|
if (block.IsTotallyFree())
|
||||||
|
{
|
||||||
|
_lock.EnterWriteLock();
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
for (int i = 0; i < _blocks.Count; i++)
|
for (int i = 0; i < _blocks.Count; i++)
|
||||||
{
|
{
|
||||||
@@ -252,12 +269,21 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_lock.ExitWriteLock();
|
||||||
|
}
|
||||||
|
|
||||||
block.Destroy(_api, _device);
|
block.Destroy(_api, _device);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InsertBlock(Block block)
|
private void InsertBlock(Block block)
|
||||||
|
{
|
||||||
|
_lock.EnterWriteLock();
|
||||||
|
|
||||||
|
try
|
||||||
{
|
{
|
||||||
int index = _blocks.BinarySearch(block);
|
int index = _blocks.BinarySearch(block);
|
||||||
if (index < 0)
|
if (index < 0)
|
||||||
@@ -267,6 +293,11 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
_blocks.Insert(index, block);
|
_blocks.Insert(index, block);
|
||||||
}
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_lock.ExitWriteLock();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
|
@@ -1,5 +1,6 @@
|
|||||||
using Ryujinx.Graphics.GAL;
|
using Ryujinx.Graphics.GAL;
|
||||||
using Silk.NET.Vulkan;
|
using Silk.NET.Vulkan;
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
|
|
||||||
@@ -7,15 +8,28 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
{
|
{
|
||||||
class PipelineLayoutCacheEntry
|
class PipelineLayoutCacheEntry
|
||||||
{
|
{
|
||||||
|
// Those were adjusted based on current descriptor usage and the descriptor counts usually used on pipeline layouts.
|
||||||
|
// It might be a good idea to tweak them again if those change, or maybe find a way to calculate an optimal value dynamically.
|
||||||
|
private const uint DefaultUniformBufferPoolCapacity = 19 * DescriptorSetManager.MaxSets;
|
||||||
|
private const uint DefaultStorageBufferPoolCapacity = 16 * DescriptorSetManager.MaxSets;
|
||||||
|
private const uint DefaultTexturePoolCapacity = 128 * DescriptorSetManager.MaxSets;
|
||||||
|
private const uint DefaultImagePoolCapacity = 8 * DescriptorSetManager.MaxSets;
|
||||||
|
|
||||||
|
private const int MaxPoolSizesPerSet = 2;
|
||||||
|
|
||||||
private readonly VulkanRenderer _gd;
|
private readonly VulkanRenderer _gd;
|
||||||
private readonly Device _device;
|
private readonly Device _device;
|
||||||
|
|
||||||
public DescriptorSetLayout[] DescriptorSetLayouts { get; }
|
public DescriptorSetLayout[] DescriptorSetLayouts { get; }
|
||||||
public PipelineLayout PipelineLayout { get; }
|
public PipelineLayout PipelineLayout { get; }
|
||||||
|
|
||||||
|
private readonly int[] _consumedDescriptorsPerSet;
|
||||||
|
|
||||||
private readonly List<Auto<DescriptorSetCollection>>[][] _dsCache;
|
private readonly List<Auto<DescriptorSetCollection>>[][] _dsCache;
|
||||||
|
private List<Auto<DescriptorSetCollection>>[] _currentDsCache;
|
||||||
private readonly int[] _dsCacheCursor;
|
private readonly int[] _dsCacheCursor;
|
||||||
private int _dsLastCbIndex;
|
private int _dsLastCbIndex;
|
||||||
|
private int _dsLastSubmissionCount;
|
||||||
|
|
||||||
private PipelineLayoutCacheEntry(VulkanRenderer gd, Device device, int setsCount)
|
private PipelineLayoutCacheEntry(VulkanRenderer gd, Device device, int setsCount)
|
||||||
{
|
{
|
||||||
@@ -44,29 +58,55 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
bool usePushDescriptors) : this(gd, device, setDescriptors.Count)
|
bool usePushDescriptors) : this(gd, device, setDescriptors.Count)
|
||||||
{
|
{
|
||||||
(DescriptorSetLayouts, PipelineLayout) = PipelineLayoutFactory.Create(gd, device, setDescriptors, usePushDescriptors);
|
(DescriptorSetLayouts, PipelineLayout) = PipelineLayoutFactory.Create(gd, device, setDescriptors, usePushDescriptors);
|
||||||
|
|
||||||
|
_consumedDescriptorsPerSet = new int[setDescriptors.Count];
|
||||||
|
|
||||||
|
for (int setIndex = 0; setIndex < setDescriptors.Count; setIndex++)
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
foreach (var descriptor in setDescriptors[setIndex].Descriptors)
|
||||||
|
{
|
||||||
|
count += descriptor.Count;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Auto<DescriptorSetCollection> GetNewDescriptorSetCollection(
|
_consumedDescriptorsPerSet[setIndex] = count;
|
||||||
VulkanRenderer gd,
|
}
|
||||||
int commandBufferIndex,
|
}
|
||||||
int setIndex,
|
|
||||||
out bool isNew)
|
public void UpdateCommandBufferIndex(int commandBufferIndex)
|
||||||
{
|
{
|
||||||
if (_dsLastCbIndex != commandBufferIndex)
|
int submissionCount = _gd.CommandBufferPool.GetSubmissionCount(commandBufferIndex);
|
||||||
|
|
||||||
|
if (_dsLastCbIndex != commandBufferIndex || _dsLastSubmissionCount != submissionCount)
|
||||||
{
|
{
|
||||||
_dsLastCbIndex = commandBufferIndex;
|
_dsLastCbIndex = commandBufferIndex;
|
||||||
|
_dsLastSubmissionCount = submissionCount;
|
||||||
|
Array.Clear(_dsCacheCursor);
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < _dsCacheCursor.Length; i++)
|
_currentDsCache = _dsCache[commandBufferIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
public Auto<DescriptorSetCollection> GetNewDescriptorSetCollection(int setIndex, out bool isNew)
|
||||||
{
|
{
|
||||||
_dsCacheCursor[i] = 0;
|
var list = _currentDsCache[setIndex];
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
var list = _dsCache[commandBufferIndex][setIndex];
|
|
||||||
int index = _dsCacheCursor[setIndex]++;
|
int index = _dsCacheCursor[setIndex]++;
|
||||||
if (index == list.Count)
|
if (index == list.Count)
|
||||||
{
|
{
|
||||||
var dsc = gd.DescriptorSetManager.AllocateDescriptorSet(gd.Api, DescriptorSetLayouts[setIndex]);
|
Span<DescriptorPoolSize> poolSizes = stackalloc DescriptorPoolSize[MaxPoolSizesPerSet];
|
||||||
|
poolSizes = GetDescriptorPoolSizes(poolSizes, setIndex);
|
||||||
|
|
||||||
|
int consumedDescriptors = _consumedDescriptorsPerSet[setIndex];
|
||||||
|
|
||||||
|
var dsc = _gd.DescriptorSetManager.AllocateDescriptorSet(
|
||||||
|
_gd.Api,
|
||||||
|
DescriptorSetLayouts[setIndex],
|
||||||
|
poolSizes,
|
||||||
|
setIndex,
|
||||||
|
consumedDescriptors,
|
||||||
|
false);
|
||||||
|
|
||||||
list.Add(dsc);
|
list.Add(dsc);
|
||||||
isNew = true;
|
isNew = true;
|
||||||
return dsc;
|
return dsc;
|
||||||
@@ -76,6 +116,33 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return list[index];
|
return list[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Span<DescriptorPoolSize> GetDescriptorPoolSizes(Span<DescriptorPoolSize> output, int setIndex)
|
||||||
|
{
|
||||||
|
int count = 1;
|
||||||
|
|
||||||
|
switch (setIndex)
|
||||||
|
{
|
||||||
|
case PipelineBase.UniformSetIndex:
|
||||||
|
output[0] = new(DescriptorType.UniformBuffer, DefaultUniformBufferPoolCapacity);
|
||||||
|
break;
|
||||||
|
case PipelineBase.StorageSetIndex:
|
||||||
|
output[0] = new(DescriptorType.StorageBuffer, DefaultStorageBufferPoolCapacity);
|
||||||
|
break;
|
||||||
|
case PipelineBase.TextureSetIndex:
|
||||||
|
output[0] = new(DescriptorType.CombinedImageSampler, DefaultTexturePoolCapacity);
|
||||||
|
output[1] = new(DescriptorType.UniformTexelBuffer, DefaultTexturePoolCapacity);
|
||||||
|
count = 2;
|
||||||
|
break;
|
||||||
|
case PipelineBase.ImageSetIndex:
|
||||||
|
output[0] = new(DescriptorType.StorageImage, DefaultImagePoolCapacity);
|
||||||
|
output[1] = new(DescriptorType.StorageTexelBuffer, DefaultImagePoolCapacity);
|
||||||
|
count = 2;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return output[..count];
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual unsafe void Dispose(bool disposing)
|
protected virtual unsafe void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (disposing)
|
if (disposing)
|
||||||
|
@@ -464,13 +464,14 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Auto<DescriptorSetCollection> GetNewDescriptorSetCollection(
|
public void UpdateDescriptorCacheCommandBufferIndex(int commandBufferIndex)
|
||||||
VulkanRenderer gd,
|
|
||||||
int commandBufferIndex,
|
|
||||||
int setIndex,
|
|
||||||
out bool isNew)
|
|
||||||
{
|
{
|
||||||
return _plce.GetNewDescriptorSetCollection(gd, commandBufferIndex, setIndex, out isNew);
|
_plce.UpdateCommandBufferIndex(commandBufferIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Auto<DescriptorSetCollection> GetNewDescriptorSetCollection(int setIndex, out bool isNew)
|
||||||
|
{
|
||||||
|
return _plce.GetNewDescriptorSetCollection(setIndex, out isNew);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void Dispose(bool disposing)
|
protected virtual void Dispose(bool disposing)
|
||||||
|
@@ -347,7 +347,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||||||
|
|
||||||
CommandBufferPool = new CommandBufferPool(Api, _device, Queue, QueueLock, queueFamilyIndex);
|
CommandBufferPool = new CommandBufferPool(Api, _device, Queue, QueueLock, queueFamilyIndex);
|
||||||
|
|
||||||
DescriptorSetManager = new DescriptorSetManager(_device);
|
DescriptorSetManager = new DescriptorSetManager(_device, PipelineBase.DescriptorSetLayouts);
|
||||||
|
|
||||||
PipelineLayoutCache = new PipelineLayoutCache();
|
PipelineLayoutCache = new PipelineLayoutCache();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user