diff options
Diffstat (limited to 'src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs')
-rw-r--r-- | src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs | 106 |
1 files changed, 76 insertions, 30 deletions
diff --git a/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs b/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs index 1694049c..334dfc20 100644 --- a/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs +++ b/src/Ryujinx.Graphics.Vulkan/ShaderCollection.cs @@ -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)); |