mirror of
https://git.743378673.xyz/MeloNX/MeloNX.git
synced 2025-06-29 11:56:24 +02:00
Replace ShaderBindings with new ResourceLayout structure for Vulkan (#5025)
* Introduce ResourceLayout * Part 1: Use new ResourceSegments array on UpdateAndBind * Part 2: Use ResourceLayout to build PipelineLayout * Delete old code * XML docs * Fix shader cache load NRE * Fix typo
This commit is contained in:
parent
402f05b8ef
commit
5626f2ca1c
24 changed files with 1047 additions and 677 deletions
|
@ -3,6 +3,7 @@ using Ryujinx.Graphics.GAL;
|
|||
using Silk.NET.Vulkan;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
|
@ -23,7 +24,7 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
public uint Stages { get; }
|
||||
|
||||
public int[][][] Bindings { get; }
|
||||
public ResourceBindingSegment[][] BindingSegments { get; }
|
||||
|
||||
public ProgramLinkStatus LinkStatus { get; private set; }
|
||||
|
||||
|
@ -54,7 +55,13 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
private Task _compileTask;
|
||||
private bool _firstBackgroundUse;
|
||||
|
||||
public ShaderCollection(VulkanRenderer gd, Device device, ShaderSource[] shaders, SpecDescription[] specDescription = null, bool isMinimal = false)
|
||||
public ShaderCollection(
|
||||
VulkanRenderer gd,
|
||||
Device device,
|
||||
ShaderSource[] shaders,
|
||||
ResourceLayout resourceLayout,
|
||||
SpecDescription[] specDescription = null,
|
||||
bool isMinimal = false)
|
||||
{
|
||||
_gd = gd;
|
||||
_device = device;
|
||||
|
@ -99,39 +106,16 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
|
||||
_shaders = internalShaders;
|
||||
|
||||
bool usePd = !isMinimal && VulkanConfiguration.UsePushDescriptors && _gd.Capabilities.SupportsPushDescriptors;
|
||||
bool usePushDescriptors = !isMinimal && VulkanConfiguration.UsePushDescriptors && _gd.Capabilities.SupportsPushDescriptors;
|
||||
|
||||
_plce = isMinimal
|
||||
? gd.PipelineLayoutCache.Create(gd, device, shaders)
|
||||
: gd.PipelineLayoutCache.GetOrCreate(gd, device, stages, usePd);
|
||||
_plce = gd.PipelineLayoutCache.GetOrCreate(gd, device, resourceLayout.Sets, usePushDescriptors);
|
||||
|
||||
HasMinimalLayout = isMinimal;
|
||||
UsePushDescriptors = usePd;
|
||||
UsePushDescriptors = usePushDescriptors;
|
||||
|
||||
Stages = stages;
|
||||
|
||||
int[][] GrabAll(Func<ShaderBindings, IReadOnlyCollection<int>> selector)
|
||||
{
|
||||
bool hasAny = false;
|
||||
int[][] bindings = new int[internalShaders.Length][];
|
||||
|
||||
for (int i = 0; i < internalShaders.Length; i++)
|
||||
{
|
||||
var collection = selector(internalShaders[i].Bindings);
|
||||
hasAny |= collection.Count != 0;
|
||||
bindings[i] = collection.ToArray();
|
||||
}
|
||||
|
||||
return hasAny ? bindings : Array.Empty<int[]>();
|
||||
}
|
||||
|
||||
Bindings = new[]
|
||||
{
|
||||
GrabAll(x => x.UniformBufferBindings),
|
||||
GrabAll(x => x.StorageBufferBindings),
|
||||
GrabAll(x => x.TextureBindings),
|
||||
GrabAll(x => x.ImageBindings)
|
||||
};
|
||||
BindingSegments = BuildBindingSegments(resourceLayout.SetUsages);
|
||||
|
||||
_compileTask = Task.CompletedTask;
|
||||
_firstBackgroundUse = false;
|
||||
|
@ -141,8 +125,9 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
VulkanRenderer gd,
|
||||
Device device,
|
||||
ShaderSource[] sources,
|
||||
ResourceLayout resourceLayout,
|
||||
ProgramPipelineState state,
|
||||
bool fromCache) : this(gd, device, sources)
|
||||
bool fromCache) : this(gd, device, sources, resourceLayout)
|
||||
{
|
||||
_state = state;
|
||||
|
||||
|
@ -150,6 +135,67 @@ namespace Ryujinx.Graphics.Vulkan
|
|||
_firstBackgroundUse = !fromCache;
|
||||
}
|
||||
|
||||
private static ResourceBindingSegment[][] BuildBindingSegments(ReadOnlyCollection<ResourceUsageCollection> setUsages)
|
||||
{
|
||||
ResourceBindingSegment[][] segments = new ResourceBindingSegment[setUsages.Count][];
|
||||
|
||||
for (int setIndex = 0; setIndex < setUsages.Count; setIndex++)
|
||||
{
|
||||
List<ResourceBindingSegment> currentSegments = new List<ResourceBindingSegment>();
|
||||
|
||||
ResourceUsage currentUsage = default;
|
||||
int currentCount = 0;
|
||||
|
||||
for (int index = 0; index < setUsages[setIndex].Usages.Count; index++)
|
||||
{
|
||||
ResourceUsage usage = setUsages[setIndex].Usages[index];
|
||||
|
||||
// If the resource is not accessed, we don't need to update it.
|
||||
if (usage.Access == ResourceAccess.None)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (currentUsage.Binding + currentCount != usage.Binding ||
|
||||
currentUsage.Type != usage.Type ||
|
||||
currentUsage.Stages != usage.Stages ||
|
||||
currentUsage.Access != usage.Access)
|
||||
{
|
||||
if (currentCount != 0)
|
||||
{
|
||||
currentSegments.Add(new ResourceBindingSegment(
|
||||
currentUsage.Binding,
|
||||
currentCount,
|
||||
currentUsage.Type,
|
||||
currentUsage.Stages,
|
||||
currentUsage.Access));
|
||||
}
|
||||
|
||||
currentUsage = usage;
|
||||
currentCount = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
currentCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (currentCount != 0)
|
||||
{
|
||||
currentSegments.Add(new ResourceBindingSegment(
|
||||
currentUsage.Binding,
|
||||
currentCount,
|
||||
currentUsage.Type,
|
||||
currentUsage.Stages,
|
||||
currentUsage.Access));
|
||||
}
|
||||
|
||||
segments[setIndex] = currentSegments.ToArray();
|
||||
}
|
||||
|
||||
return segments;
|
||||
}
|
||||
|
||||
private async Task BackgroundCompilation()
|
||||
{
|
||||
await Task.WhenAll(_shaders.Select(shader => shader.CompileTask));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue