diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2020-11-08 08:10:00 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2020-11-08 12:10:00 +0100 |
| commit | 8d168574eb04ae1e7026ac2b058e3b184f068fae (patch) | |
| tree | 6e0f79447276619af980055419874f5e99595b58 /Ryujinx.Graphics.Gpu | |
| parent | 5561a3b95e9c980e3354366570e7896a213b95ae (diff) | |
Use explicit buffer and texture bindings on shaders (#1666)
* Use explicit buffer and texture bindings on shaders
* More XML docs and other nits
Diffstat (limited to 'Ryujinx.Graphics.Gpu')
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Engine/Compute.cs | 36 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Engine/Methods.cs | 32 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs | 28 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs | 36 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Memory/BufferBounds.cs | 22 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Memory/BufferManager.cs | 272 | ||||
| -rw-r--r-- | Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs | 31 |
7 files changed, 262 insertions, 195 deletions
diff --git a/Ryujinx.Graphics.Gpu/Engine/Compute.cs b/Ryujinx.Graphics.Gpu/Engine/Compute.cs index 1219ef0c..3ea98f3e 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Compute.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Compute.cs @@ -28,9 +28,6 @@ namespace Ryujinx.Graphics.Gpu.Engine int sharedMemorySize = Math.Min(qmd.SharedMemorySize, _context.Capabilities.MaximumComputeSharedMemorySize); - uint sbEnableMask = 0; - uint ubEnableMask = 0; - for (int index = 0; index < Constants.TotalCpUniformBuffers; index++) { if (!qmd.ConstantBufferValid(index)) @@ -38,8 +35,6 @@ namespace Ryujinx.Graphics.Gpu.Engine continue; } - ubEnableMask |= 1u << index; - ulong gpuVa = (uint)qmd.ConstantBufferAddrLower(index) | (ulong)qmd.ConstantBufferAddrUpper(index) << 32; ulong size = (ulong)qmd.ConstantBufferSize(index); @@ -58,13 +53,10 @@ namespace Ryujinx.Graphics.Gpu.Engine _context.Renderer.Pipeline.SetProgram(cs.HostProgram); var samplerPool = state.Get<PoolState>(MethodOffset.SamplerPoolState); - - TextureManager.SetComputeSamplerPool(samplerPool.Address.Pack(), samplerPool.MaximumId, qmd.SamplerIndex); - var texturePool = state.Get<PoolState>(MethodOffset.TexturePoolState); + TextureManager.SetComputeSamplerPool(samplerPool.Address.Pack(), samplerPool.MaximumId, qmd.SamplerIndex); TextureManager.SetComputeTexturePool(texturePool.Address.Pack(), texturePool.MaximumId); - TextureManager.SetComputeTextureBufferIndex(state.Get<int>(MethodOffset.TextureBufferIndex)); ShaderProgramInfo info = cs.Shaders[0].Program.Info; @@ -82,8 +74,6 @@ namespace Ryujinx.Graphics.Gpu.Engine continue; } - ubEnableMask |= 1u << cb.Slot; - ulong cbDescAddress = BufferManager.GetComputeUniformBufferAddress(0); int cbDescOffset = 0x260 + (cb.Slot - 8) * 0x10; @@ -99,8 +89,6 @@ namespace Ryujinx.Graphics.Gpu.Engine { BufferDescriptor sb = info.SBuffers[index]; - sbEnableMask |= 1u << sb.Slot; - ulong sbDescAddress = BufferManager.GetComputeUniformBufferAddress(0); int sbDescOffset = 0x310 + sb.Slot * 0x10; @@ -112,15 +100,8 @@ namespace Ryujinx.Graphics.Gpu.Engine BufferManager.SetComputeStorageBuffer(sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size); } - ubEnableMask = 0; - - for (int index = 0; index < info.CBuffers.Count; index++) - { - ubEnableMask |= 1u << info.CBuffers[index].Slot; - } - - BufferManager.SetComputeStorageBufferEnableMask(sbEnableMask); - BufferManager.SetComputeUniformBufferEnableMask(ubEnableMask); + BufferManager.SetComputeStorageBufferBindings(info.SBuffers); + BufferManager.SetComputeUniformBufferBindings(info.CBuffers); var textureBindings = new TextureBindingInfo[info.Textures.Count]; @@ -132,11 +113,16 @@ namespace Ryujinx.Graphics.Gpu.Engine if (descriptor.IsBindless) { - textureBindings[index] = new TextureBindingInfo(target, descriptor.CbufOffset, descriptor.CbufSlot, descriptor.Flags); + textureBindings[index] = new TextureBindingInfo( + target, + descriptor.Binding, + descriptor.CbufOffset, + descriptor.CbufSlot, + descriptor.Flags); } else { - textureBindings[index] = new TextureBindingInfo(target, descriptor.HandleIndex, descriptor.Flags); + textureBindings[index] = new TextureBindingInfo(target, descriptor.Binding, descriptor.HandleIndex, descriptor.Flags); } } @@ -151,7 +137,7 @@ namespace Ryujinx.Graphics.Gpu.Engine Target target = ShaderTexture.GetTarget(descriptor.Type); Format format = ShaderTexture.GetFormat(descriptor.Format); - imageBindings[index] = new TextureBindingInfo(target, format, descriptor.HandleIndex, descriptor.Flags); + imageBindings[index] = new TextureBindingInfo(target, format, descriptor.Binding, descriptor.HandleIndex, descriptor.Flags); } TextureManager.SetComputeImages(imageBindings); diff --git a/Ryujinx.Graphics.Gpu/Engine/Methods.cs b/Ryujinx.Graphics.Gpu/Engine/Methods.cs index d4988f35..8bc2c22d 100644 --- a/Ryujinx.Graphics.Gpu/Engine/Methods.cs +++ b/Ryujinx.Graphics.Gpu/Engine/Methods.cs @@ -6,6 +6,7 @@ using Ryujinx.Graphics.Gpu.Shader; using Ryujinx.Graphics.Gpu.State; using Ryujinx.Graphics.Shader; using System; +using System.Linq; using System.Runtime.InteropServices; namespace Ryujinx.Graphics.Gpu.Engine @@ -997,6 +998,9 @@ namespace Ryujinx.Graphics.Gpu.Engine _vsUsesInstanceId = gs.Shaders[0]?.Program.Info.UsesInstanceId ?? false; + int storageBufferBindingsCount = 0; + int uniformBufferBindingsCount = 0; + for (int stage = 0; stage < Constants.ShaderStages; stage++) { ShaderProgramInfo info = gs.Shaders[stage]?.Program.Info; @@ -1005,6 +1009,10 @@ namespace Ryujinx.Graphics.Gpu.Engine if (info == null) { + TextureManager.SetGraphicsTextures(stage, Array.Empty<TextureBindingInfo>()); + TextureManager.SetGraphicsImages(stage, Array.Empty<TextureBindingInfo>()); + BufferManager.SetGraphicsStorageBufferBindings(stage, null); + BufferManager.SetGraphicsUniformBufferBindings(stage, null); continue; } @@ -1018,11 +1026,11 @@ namespace Ryujinx.Graphics.Gpu.Engine if (descriptor.IsBindless) { - textureBindings[index] = new TextureBindingInfo(target, descriptor.CbufSlot, descriptor.CbufOffset, descriptor.Flags); + textureBindings[index] = new TextureBindingInfo(target, descriptor.Binding, descriptor.CbufSlot, descriptor.CbufOffset, descriptor.Flags); } else { - textureBindings[index] = new TextureBindingInfo(target, descriptor.HandleIndex, descriptor.Flags); + textureBindings[index] = new TextureBindingInfo(target, descriptor.Binding, descriptor.HandleIndex, descriptor.Flags); } } @@ -1037,28 +1045,28 @@ namespace Ryujinx.Graphics.Gpu.Engine Target target = ShaderTexture.GetTarget(descriptor.Type); Format format = ShaderTexture.GetFormat(descriptor.Format); - imageBindings[index] = new TextureBindingInfo(target, format, descriptor.HandleIndex, descriptor.Flags); + imageBindings[index] = new TextureBindingInfo(target, format, descriptor.Binding, descriptor.HandleIndex, descriptor.Flags); } TextureManager.SetGraphicsImages(stage, imageBindings); - uint sbEnableMask = 0; - uint ubEnableMask = 0; + BufferManager.SetGraphicsStorageBufferBindings(stage, info.SBuffers); + BufferManager.SetGraphicsUniformBufferBindings(stage, info.CBuffers); - for (int index = 0; index < info.SBuffers.Count; index++) + if (info.SBuffers.Count != 0) { - sbEnableMask |= 1u << info.SBuffers[index].Slot; + storageBufferBindingsCount = Math.Max(storageBufferBindingsCount, info.SBuffers.Max(x => x.Binding) + 1); } - for (int index = 0; index < info.CBuffers.Count; index++) + if (info.CBuffers.Count != 0) { - ubEnableMask |= 1u << info.CBuffers[index].Slot; + uniformBufferBindingsCount = Math.Max(uniformBufferBindingsCount, info.CBuffers.Max(x => x.Binding) + 1); } - - BufferManager.SetGraphicsStorageBufferEnableMask(stage, sbEnableMask); - BufferManager.SetGraphicsUniformBufferEnableMask(stage, ubEnableMask); } + BufferManager.SetGraphicsStorageBufferBindingsCount(storageBufferBindingsCount); + BufferManager.SetGraphicsUniformBufferBindingsCount(uniformBufferBindingsCount); + _context.Renderer.Pipeline.SetProgram(gs.HostProgram); } diff --git a/Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs b/Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs index 422b66e2..a328fc2b 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs @@ -20,6 +20,11 @@ namespace Ryujinx.Graphics.Gpu.Image public Format Format { get; } /// <summary> + /// Shader texture host binding point. + /// </summary> + public int Binding { get; } + + /// <summary> /// Shader texture handle. /// This is an index into the texture constant buffer. /// </summary> @@ -53,13 +58,15 @@ namespace Ryujinx.Graphics.Gpu.Image /// </summary> /// <param name="target">The shader sampler target type</param> /// <param name="format">Format of the image as declared on the shader</param> + /// <param name="binding">The shader texture binding point</param> /// <param name="handle">The shader texture handle (read index into the texture constant buffer)</param> /// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param> - public TextureBindingInfo(Target target, Format format, int handle, TextureUsageFlags flags) + public TextureBindingInfo(Target target, Format format, int binding, int handle, TextureUsageFlags flags) { - Target = target; - Format = format; - Handle = handle; + Target = target; + Format = format; + Binding = binding; + Handle = handle; IsBindless = false; @@ -73,9 +80,10 @@ namespace Ryujinx.Graphics.Gpu.Image /// Constructs the texture binding information structure. /// </summary> /// <param name="target">The shader sampler target type</param> + /// <param name="binding">The shader texture binding point</param> /// <param name="handle">The shader texture handle (read index into the texture constant buffer)</param> /// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param> - public TextureBindingInfo(Target target, int handle, TextureUsageFlags flags) : this(target, (Format)0, handle, flags) + public TextureBindingInfo(Target target, int binding, int handle, TextureUsageFlags flags) : this(target, (Format)0, binding, handle, flags) { } @@ -83,14 +91,16 @@ namespace Ryujinx.Graphics.Gpu.Image /// Constructs the bindless texture binding information structure. /// </summary> /// <param name="target">The shader sampler target type</param> + /// <param name="binding">The shader texture binding point</param> /// <param name="cbufSlot">Constant buffer slot where the bindless texture handle is located</param> /// <param name="cbufOffset">Constant buffer offset of the bindless texture handle</param> /// <param name="flags">The texture's usage flags, indicating how it is used in the shader</param> - public TextureBindingInfo(Target target, int cbufSlot, int cbufOffset, TextureUsageFlags flags) + public TextureBindingInfo(Target target, int binding, int cbufSlot, int cbufOffset, TextureUsageFlags flags) { - Target = target; - Format = 0; - Handle = 0; + Target = target; + Format = 0; + Binding = binding; + Handle = 0; IsBindless = true; diff --git a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs index 08c4082e..bfb6da25 100644 --- a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs +++ b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs @@ -265,11 +265,11 @@ namespace Ryujinx.Graphics.Gpu.Image for (int index = 0; index < _textureBindings[stageIndex].Length; index++) { - TextureBindingInfo binding = _textureBindings[stageIndex][index]; + TextureBindingInfo bindingInfo = _textureBindings[stageIndex][index]; int packedId; - if (binding.IsBindless) + if (bindingInfo.IsBindless) { ulong address; @@ -277,18 +277,18 @@ namespace Ryujinx.Graphics.Gpu.Image if (_isCompute) { - address = bufferManager.GetComputeUniformBufferAddress(binding.CbufSlot); + address = bufferManager.GetComputeUniformBufferAddress(bindingInfo.CbufSlot); } else { - address = bufferManager.GetGraphicsUniformBufferAddress(stageIndex, binding.CbufSlot); + address = bufferManager.GetGraphicsUniformBufferAddress(stageIndex, bindingInfo.CbufSlot); } - packedId = _context.PhysicalMemory.Read<int>(address + (ulong)binding.CbufOffset * 4); + packedId = _context.PhysicalMemory.Read<int>(address + (ulong)bindingInfo.CbufOffset * 4); } else { - packedId = ReadPackedId(stageIndex, binding.Handle, _textureBufferIndex); + packedId = ReadPackedId(stageIndex, bindingInfo.Handle, _textureBufferIndex); } int textureId = UnpackTextureId(packedId); @@ -305,18 +305,18 @@ namespace Ryujinx.Graphics.Gpu.Image Texture texture = pool.Get(textureId); - ITexture hostTexture = texture?.GetTargetTexture(binding.Target); + ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target); if (_textureState[stageIndex][index].Texture != hostTexture || _rebind) { - if (UpdateScale(texture, binding, index, stage)) + if (UpdateScale(texture, bindingInfo, index, stage)) { - hostTexture = texture?.GetTargetTexture(binding.Target); + hostTexture = texture?.GetTargetTexture(bindingInfo.Target); } _textureState[stageIndex][index].Texture = hostTexture; - _context.Renderer.Pipeline.SetTexture(index, stage, hostTexture); + _context.Renderer.Pipeline.SetTexture(bindingInfo.Binding, hostTexture); } if (hostTexture != null && texture.Info.Target == Target.TextureBuffer) @@ -335,7 +335,7 @@ namespace Ryujinx.Graphics.Gpu.Image { _textureState[stageIndex][index].Sampler = hostSampler; - _context.Renderer.Pipeline.SetSampler(index, stage, hostSampler); + _context.Renderer.Pipeline.SetSampler(bindingInfo.Binding, hostSampler); } } } @@ -359,14 +359,14 @@ namespace Ryujinx.Graphics.Gpu.Image for (int index = 0; index < _imageBindings[stageIndex].Length; index++) { - TextureBindingInfo binding = _imageBindings[stageIndex][index]; + TextureBindingInfo bindingInfo = _imageBindings[stageIndex][index]; - int packedId = ReadPackedId(stageIndex, binding.Handle, _textureBufferIndex); + int packedId = ReadPackedId(stageIndex, bindingInfo.Handle, _textureBufferIndex); int textureId = UnpackTextureId(packedId); Texture texture = pool.Get(textureId); - ITexture hostTexture = texture?.GetTargetTexture(binding.Target); + ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target); if (hostTexture != null && texture.Info.Target == Target.TextureBuffer) { @@ -378,21 +378,21 @@ namespace Ryujinx.Graphics.Gpu.Image if (_imageState[stageIndex][index].Texture != hostTexture || _rebind) { - if (UpdateScale(texture, binding, baseScaleIndex + index, stage)) + if (UpdateScale(texture, bindingInfo, baseScaleIndex + index, stage)) { - hostTexture = texture?.GetTargetTexture(binding.Target); + hostTexture = texture?.GetTargetTexture(bindingInfo.Target); } _imageState[stageIndex][index].Texture = hostTexture; - Format format = binding.Format; + Format format = bindingInfo.Format; if (format == 0 && texture != null) { format = texture.Format; } - _context.Renderer.Pipeline.SetImage(index, stage, hostTexture, format); + _context.Renderer.Pipeline.SetImage(bindingInfo.Binding, hostTexture, format); } } } diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferBounds.cs b/Ryujinx.Graphics.Gpu/Memory/BufferBounds.cs index 42500342..060171fb 100644 --- a/Ryujinx.Graphics.Gpu/Memory/BufferBounds.cs +++ b/Ryujinx.Graphics.Gpu/Memory/BufferBounds.cs @@ -5,7 +5,25 @@ namespace Ryujinx.Graphics.Gpu.Memory /// </summary> struct BufferBounds { - public ulong Address; - public ulong Size; + /// <summary> + /// Region virtual address. + /// </summary> + public ulong Address { get; } + + /// <summary> + /// Region size in bytes. + /// </summary> + public ulong Size { get; } + + /// <summary> + /// Creates a new buffer region. + /// </summary> + /// <param name="address">Region address</param> + /// <param name="size">Region size</param> + public BufferBounds(ulong address, ulong size) + { + Address = address; + Size = size; + } } }
\ No newline at end of file diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs index eec545b9..568133ca 100644 --- a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs +++ b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs @@ -4,6 +4,8 @@ using Ryujinx.Graphics.Gpu.State; using Ryujinx.Graphics.Shader; using Ryujinx.Memory.Range; using System; +using System.Collections.ObjectModel; +using System.Linq; namespace Ryujinx.Graphics.Gpu.Memory { @@ -12,6 +14,8 @@ namespace Ryujinx.Graphics.Gpu.Memory /// </summary> class BufferManager { + private const int StackToHeapThreshold = 16; + private const int OverlapsBufferInitialCapacity = 10; private const int OverlapsBufferMaxCapacity = 10000; @@ -28,21 +32,61 @@ namespace Ryujinx.Graphics.Gpu.Memory private VertexBuffer[] _vertexBuffers; private BufferBounds[] _transformFeedbackBuffers; + /// <summary> + /// Holds shader stage buffer state and binding information. + /// </summary> private class BuffersPerStage { - public uint EnableMask { get; set; } + /// <summary> + /// Shader buffer binding information. + /// </summary> + public BufferDescriptor[] Bindings { get; } + /// <summary> + /// Buffer regions. + /// </summary> public BufferBounds[] Buffers { get; } + /// <summary> + /// Total amount of buffers used on the shader. + /// </summary> + public int Count { get; private set; } + + /// <summary> + /// Creates a new instance of the shader stage buffer information. + /// </summary> + /// <param name="count">Maximum amount of buffers that the shader stage can use</param> public BuffersPerStage(int count) { + Bindings = new BufferDescriptor[count]; Buffers = new BufferBounds[count]; } - public void Bind(int index, ulong address, ulong size) + /// <summary> + /// Sets the region of a buffer at a given slot. + /// </summary> + /// <param name="index">Buffer slot</param> + /// <param name="address">Region virtual address</param> + /// <param name="size">Region size in bytes</param> + public void SetBounds(int index, ulong address, ulong size) { - Buffers[index].Address = address; - Buffers[index].Size = size; + Buffers[index] = new BufferBounds(address, size); + } + + /// <summary> + /// Sets shader buffer binding information. + /// </summary> + /// <param name="descriptors">Buffer binding information</param> + public void SetBindings(ReadOnlyCollection<BufferDescriptor> descriptors) + { + if (descriptors == null) + { + Count = 0; + return; + } + + descriptors.CopyTo(Bindings, 0); + Count = descriptors.Count; } } @@ -51,6 +95,11 @@ namespace Ryujinx.Graphics.Gpu.Memory private BuffersPerStage[] _gpStorageBuffers; private BuffersPerStage[] _gpUniformBuffers; + private int _cpStorageBufferBindings; + private int _cpUniformBufferBindings; + private int _gpStorageBufferBindings; + private int _gpUniformBufferBindings; + private bool _gpStorageBuffersDirty; private bool _gpUniformBuffersDirty; @@ -159,9 +208,7 @@ namespace Ryujinx.Graphics.Gpu.Memory { ulong address = TranslateAndCreateBuffer(gpuVa, size); - _transformFeedbackBuffers[index].Address = address; - _transformFeedbackBuffers[index].Size = size; - + _transformFeedbackBuffers[index] = new BufferBounds(address, size); _transformFeedbackBuffersDirty = true; } @@ -180,7 +227,7 @@ namespace Ryujinx.Graphics.Gpu.Memory ulong address = TranslateAndCreateBuffer(gpuVa, size); - _cpStorageBuffers.Bind(index, address, size); + _cpStorageBuffers.SetBounds(index, address, size); } /// <summary> @@ -205,7 +252,7 @@ namespace Ryujinx.Graphics.Gpu.Memory _gpStorageBuffersDirty = true; } - _gpStorageBuffers[stage].Bind(index, address, size); + _gpStorageBuffers[stage].SetBounds(index, address, size); } /// <summary> @@ -219,7 +266,7 @@ namespace Ryujinx.Graphics.Gpu.Memory { ulong address = TranslateAndCreateBuffer(gpuVa, size); - _cpUniformBuffers.Bind(index, address, size); + _cpUniformBuffers.SetBounds(index, address, size); } /// <summary> @@ -234,42 +281,69 @@ namespace Ryujinx.Graphics.Gpu.Memory { ulong address = TranslateAndCreateBuffer(gpuVa, size); - _gpUniformBuffers[stage].Bind(index, address, size); - + _gpUniformBuffers[stage].SetBounds(index, address, size); _gpUniformBuffersDirty = true; } /// <summary> - /// Sets the enabled storage buffers mask on the compute pipeline. - /// Each bit set on the mask indicates that the respective buffer index is enabled. + /// Sets the binding points for the storage buffers bound on the compute pipeline. /// </summary> - /// <param name="mask">Buffer enable mask</param> - public void SetComputeStorageBufferEnableMask(uint mask) + /// <param name="descriptors">Buffer descriptors with the binding point values</param> + public void SetComputeStorageBufferBindings(ReadOnlyCollection<BufferDescriptor> descriptors) { - _cpStorageBuffers.EnableMask = mask; + _cpStorageBuffers.SetBindings(descriptors); + _cpStorageBufferBindings = descriptors.Count != 0 ? descriptors.Max(x => x.Binding) + 1 : 0; } /// <summary> - /// Sets the enabled storage buffers mask on the graphics pipeline. - /// Each bit set on the mask indicates that the respective buffer index is enabled. + /// Sets the binding points for the storage buffers bound on the graphics pipeline. /// </summary> /// <param name="stage">Index of the shader stage</param> - /// <param name="mask">Buffer enable mask</param> - public void SetGraphicsStorageBufferEnableMask(int stage, uint mask) + /// <param name="descriptors">Buffer descriptors with the binding point values</param> + public void SetGraphicsStorageBufferBindings(int stage, ReadOnlyCollection<BufferDescriptor> descriptors) { - _gpStorageBuffers[stage].EnableMask = mask; - + _gpStorageBuffers[stage].SetBindings(descriptors); _gpStorageBuffersDirty = true; } /// <summary> - /// Sets the enabled uniform buffers mask on the compute pipeline. + /// Sets the total number of storage buffer bindings used. + /// </summary> + /// <param name="count">Number of storage buffer bindings used</param> + public void SetGraphicsStorageBufferBindingsCount(int count) + { + _gpStorageBufferBindings = count; + } + + /// <summary> + /// Sets the binding points for the uniform buffers bound on the compute pipeline. + /// </summary> + /// <param name="descriptors">Buffer descriptors with the binding point values</param> + public void SetComputeUniformBufferBindings(ReadOnlyCollection<BufferDescriptor> descriptors) + { + _cpUniformBuffers.SetBindings(descriptors); + _cpUniformBufferBindings = descriptors.Count != 0 ? descriptors.Max(x => x.Binding) + 1 : 0; + } + + /// <summary> + /// Sets the enabled uniform buffers mask on the graphics pipeline. /// Each bit set on the mask indicates that the respective buffer index is enabled. /// </summary> - /// <param name="mask">Buffer enable mask</param> - public void SetComputeUniformBufferEnableMask(uint mask) + /// <param name="stage">Index of the shader stage</param> + /// <param name="descriptors">Buffer descriptors with the binding point values</param> + public void SetGraphicsUniformBufferBindings(int stage, ReadOnlyCollection<BufferDescriptor> descriptors) { - _cpUniformBuffers.EnableMask = mask; + _gpUniformBuffers[stage].SetBindings(descriptors); + _gpUniformBuffersDirty = true; + } + + /// <summary> + /// Sets the total number of uniform buffer bindings used. + /// </summary> + /// <param name="count">Number of uniform buffer bindings used</param> + public void SetGraphicsUniformBufferBindingsCount(int count) + { + _gpUniformBufferBindings = count; } /// <summary> @@ -292,19 +366,6 @@ namespace Ryujinx.Graphics.Gpu.Memory } /// <summary> - /// Sets the enabled uniform buffers mask on the graphics pipeline. - /// Each bit set on the mask indicates that the respective buffer index is enabled. - /// </summary> - /// <param name="stage">Index of the shader stage</param> - /// <param name="mask">Buffer enable mask</param> - public void SetGraphicsUniformBufferEnableMask(int stage, uint mask) - { - _gpUniformBuffers[stage].EnableMask = mask; - - _gpUniformBuffersDirty = true; - } - - /// <summary> /// Gets a bit mask indicating which graphics uniform buffers are currently bound. /// </summary> /// <param name="stage">Index of the shader stage</param> @@ -476,48 +537,42 @@ namespace Ryujinx.Graphics.Gpu.Memory /// </summary> public void CommitComputeBindings() { - uint enableMask = _cpStorageBuffers.EnableMask; + int sCount = _cpStorageBufferBindings; - for (int index = 0; (enableMask >> index) != 0; index++) + Span<BufferRange> sRanges = sCount < StackToHeapThreshold ? stackalloc BufferRange[sCount] : new BufferRange[sCount]; + + for (int index = 0; index < _cpStorageBuffers.Count; index++) { - if ((enableMask & (1u << index)) == 0) - { - continue; - } + ref var bindingInfo = ref _cpStorageBuffers.Bindings[index]; - BufferBounds bounds = _cpStorageBuffers.Buffers[index]; + BufferBounds bounds = _cpStorageBuffers.Buffers[bindingInfo.Slot]; - if (bounds.Address == 0) + if (bounds.Address != 0) { - continue; + sRanges[bindingInfo.Binding] = GetBufferRange(bounds.Address, bounds.Size); } + } - BufferRange buffer = GetBufferRange(bounds.Address, bounds.Size); + _context.Renderer.Pipeline.SetStorageBuffers(sRanges); - _context.Renderer.Pipeline.SetStorageBuffer(index, ShaderStage.Compute, buffer); - } + int uCount = _cpUniformBufferBindings; - enableMask = _cpUniformBuffers.EnableMask; + Span<BufferRange> uRanges = uCount < StackToHeapThreshold ? stackalloc BufferRange[uCount] : new BufferRange[uCount]; - for (int index = 0; (enableMask >> index) != 0; index++) + for (int index = 0; index < _cpUniformBuffers.Count; index++) { - if ((enableMask & (1u << index)) == 0) - { - continue; - } + ref var bindingInfo = ref _cpUniformBuffers.Bindings[index]; - BufferBounds bounds = _cpUniformBuffers.Buffers[index]; + BufferBounds bounds = _cpUniformBuffers.Buffers[bindingInfo.Slot]; - if (bounds.Address == 0) + if (bounds.Address != 0) { - continue; + uRanges[bindingInfo.Binding] = GetBufferRange(bounds.Address, bounds.Size); } - - BufferRange buffer = GetBufferRange(bounds.Address, bounds.Size); - - _context.Renderer.Pipeline.SetUniformBuffer(index, ShaderStage.Compute, buffer); } + _context.Renderer.Pipeline.SetUniformBuffers(uRanges); + // Force rebind after doing compute work. _rebind = true; } @@ -651,7 +706,35 @@ namespace Ryujinx.Graphics.Gpu.Memory /// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffers</param> private void BindBuffers(BuffersPerStage[] bindings, bool isStorage) { - BindOrUpdateBuffers(bindings, bind: true, isStorage); + int count = isStorage ? _gpStorageBufferBindings : _gpUniformBufferBindings; + + Span<BufferRange> ranges = count < StackToHeapThreshold ? stackalloc BufferRange[count] : new BufferRange[count]; + + for (ShaderStage stage = ShaderStage.Vertex; stage <= ShaderStage.Fragment; stage++) + { + ref var buffers = ref bindings[(int)stage - 1]; + + for (int index = 0; index < buffers.Count; index++) + { + ref var bindingInfo = ref buffers.Bindings[index]; + + BufferBounds bounds = buffers.Buffers[bindingInfo.Slot]; + + if (bounds.Address != 0) + { + ranges[bindingInfo.Binding] = GetBufferRange(bounds.Address, bounds.Size); + } + } + } + + if (isStorage) + { + _context.Renderer.Pipeline.SetStorageBuffers(ranges); + } + else + { + _context.Renderer.Pipeline.SetUniformBuffers(ranges); + } } /// <summary> @@ -660,74 +743,27 @@ namespace Ryujinx.Graphics.Gpu.Memory /// <param name="bindings">Bindings to update</param> private void UpdateBuffers(BuffersPerStage[] bindings) { - BindOrUpdateBuffers(bindings, bind: false); - } - - /// <summary> - /// This binds buffers into the host API, or updates data for already bound buffers. - /// </summary> - /// <param name="bindings">Bindings to bind or update</param> - /// <param name="bind">True to bind, false to update</param> - /// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffer</param> - private void BindOrUpdateBuffers(BuffersPerStage[] bindings, bool bind, bool isStorage = false) - { for (ShaderStage stage = ShaderStage.Vertex; stage <= ShaderStage.Fragment; stage++) { - uint enableMask = bindings[(int)stage - 1].EnableMask; + ref var buffers = ref bindings[(int)stage - 1]; - if (enableMask == 0) + for (int index = 0; index < buffers.Count; index++) { - continue; - } + ref var binding = ref buffers.Bindings[index]; - for (int index = 0; (enableMask >> index) != 0; index++) - { - if ((enableMask & (1u << index)) == 0) - { - continue; - } - - BufferBounds bounds = bindings[(int)stage - 1].Buffers[index]; + BufferBounds bounds = buffers.Buffers[binding.Slot]; if (bounds.Address == 0) { continue; } - if (bind) - { - BindBuffer(index, stage, bounds, isStorage); - } - else - { - SynchronizeBufferRange(bounds.Address, bounds.Size); - } + SynchronizeBufferRange(bounds.Address, bounds.Size); } } } /// <summary> - /// Binds a buffer on the host API. - /// </summary> - /// <param name="index">Index to bind the buffer into</param> - /// <param name="stage">Shader stage to bind the buffer into</param> - /// <param name="bounds">Buffer address and size</param> - /// <param name="isStorage">True to bind as storage buffer, false to bind as uniform buffer</param> - private void BindBuffer(int index, ShaderStage stage, BufferBounds bounds, bool isStorage) - { - BufferRange buffer = GetBufferRange(bounds.Address, bounds.Size); - - if (isStorage) - { - _context.Renderer.Pipeline.SetStorageBuffer(index, stage, buffer); - } - else - { - _context.Renderer.Pipeline.SetUniformBuffer(index, stage, buffer); - } - } - - /// <summary> /// Sets the buffer storage of a buffer texture. /// </summary> /// <param name="texture">Buffer texture</param> diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs index 853351db..131aa6b7 100644 --- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs +++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs @@ -80,7 +80,7 @@ namespace Ryujinx.Graphics.Gpu.Shader localMemorySize, sharedMemorySize); - shader.HostShader = _context.Renderer.CompileShader(shader.Program); + shader.HostShader = _context.Renderer.CompileShader(ShaderStage.Compute, shader.Program.Code); IProgram hostProgram = _context.Renderer.CreateProgram(new IShader[] { shader.HostShader }, null); @@ -134,19 +134,21 @@ namespace Ryujinx.Graphics.Gpu.Shader flags |= TranslationFlags.Feedback; } + TranslationCounts counts = new TranslationCounts(); + if (addresses.VertexA != 0) { - shaders[0] = TranslateGraphicsShader(state, flags, ShaderStage.Vertex, addresses.Vertex, addresses.VertexA); + shaders[0] = TranslateGraphicsShader(state, counts, flags, ShaderStage.Vertex, addresses.Vertex, addresses.VertexA); } else { - shaders[0] = TranslateGraphicsShader(state, flags, ShaderStage.Vertex, addresses.Vertex); + shaders[0] = TranslateGraphicsShader(state, counts, flags, ShaderStage.Vertex, addresses.Vertex); } - shaders[1] = TranslateGraphicsShader(state, flags, ShaderStage.TessellationControl, addresses.TessControl); - shaders[2] = TranslateGraphicsShader(state, flags, ShaderStage.TessellationEvaluation, addresses.TessEvaluation); - shaders[3] = TranslateGraphicsShader(state, flags, ShaderStage.Geometry, addresses.Geometry); - shaders[4] = TranslateGraphicsShader(state, flags, ShaderStage.Fragment, addresses.Fragment); + shaders[1] = TranslateGraphicsShader(state, counts, flags, ShaderStage.TessellationControl, addresses.TessControl); + shaders[2] = TranslateGraphicsShader(state, counts, flags, ShaderStage.TessellationEvaluation, addresses.TessEvaluation); + shaders[3] = TranslateGraphicsShader(state, counts, flags, ShaderStage.Geometry, addresses.Geometry); + shaders[4] = TranslateGraphicsShader(state, counts, flags, ShaderStage.Fragment, addresses.Fragment); List<IShader> hostShaders = new List<IShader>(); @@ -159,7 +161,7 @@ namespace Ryujinx.Graphics.Gpu.Shader continue; } - IShader hostShader = _context.Renderer.CompileShader(program); + IShader hostShader = _context.Renderer.CompileShader(program.Stage, program.Code); shaders[stage].HostShader = hostShader; @@ -334,12 +336,19 @@ namespace Ryujinx.Graphics.Gpu.Shader /// This will combine the "Vertex A" and "Vertex B" shader stages, if specified, into one shader. /// </remarks> /// <param name="state">Current GPU state</param> + /// <param name="counts">Cumulative shader resource counts</param> /// <param name="flags">Flags that controls shader translation</param> /// <param name="stage">Shader stage</param> /// <param name="gpuVa">GPU virtual address of the shader code</param> /// <param name="gpuVaA">Optional GPU virtual address of the "Vertex A" shader code</param> /// <returns>Compiled graphics shader code</returns> - private ShaderCodeHolder TranslateGraphicsShader(GpuState state, TranslationFlags flags, ShaderStage stage, ulong gpuVa, ulong gpuVaA = 0) + private ShaderCodeHolder TranslateGraphicsShader( + GpuState state, + TranslationCounts counts, + TranslationFlags flags, + ShaderStage stage, + ulong gpuVa, + ulong gpuVaA = 0) { if (gpuVa == 0) { @@ -350,7 +359,7 @@ namespace Ryujinx.Graphics.Gpu.Shader if (gpuVaA != 0) { - ShaderProgram program = Translator.Translate(gpuVaA, gpuVa, gpuAccessor, flags); + ShaderProgram program = Translator.Translate(gpuVaA, gpuVa, gpuAccessor, flags, counts); byte[] codeA = _context.MemoryManager.GetSpan(gpuVaA, program.SizeA).ToArray(); byte[] codeB = _context.MemoryManager.GetSpan(gpuVa, program.Size).ToArray(); @@ -370,7 +379,7 @@ namespace Ryujinx.Graphics.Gpu.Shader } else { - ShaderProgram program = Translator.Translate(gpuVa, gpuAccessor, flags); + ShaderProgram program = Translator.Translate(gpuVa, gpuAccessor, flags, counts); byte[] code = _context.MemoryManager.GetSpan(gpuVa, program.Size).ToArray(); |
