diff --git a/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs b/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs
index cd509471e9..2ac738fdfb 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Compute/ComputeClass.cs
@@ -202,57 +202,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Compute
_channel.BufferManager.SetComputeUniformBuffer(cb.Slot, cbDescriptor.PackAddress(), (uint)cbDescriptor.Size);
}
- _channel.BufferManager.SetComputeStorageBufferBindings(info.SBuffers);
- _channel.BufferManager.SetComputeUniformBufferBindings(info.CBuffers);
+ _channel.BufferManager.SetComputeBufferBindings(cs.Bindings);
- int maxTextureBinding = -1;
- int maxImageBinding = -1;
-
- TextureBindingInfo[] textureBindings = _channel.TextureManager.RentComputeTextureBindings(info.Textures.Count);
-
- for (int index = 0; index < info.Textures.Count; index++)
- {
- var descriptor = info.Textures[index];
-
- Target target = ShaderTexture.GetTarget(descriptor.Type);
-
- textureBindings[index] = new TextureBindingInfo(
- target,
- descriptor.Binding,
- descriptor.CbufSlot,
- descriptor.HandleIndex,
- descriptor.Flags);
-
- if (descriptor.Binding > maxTextureBinding)
- {
- maxTextureBinding = descriptor.Binding;
- }
- }
-
- TextureBindingInfo[] imageBindings = _channel.TextureManager.RentComputeImageBindings(info.Images.Count);
-
- for (int index = 0; index < info.Images.Count; index++)
- {
- var descriptor = info.Images[index];
-
- Target target = ShaderTexture.GetTarget(descriptor.Type);
- Format format = ShaderTexture.GetFormat(descriptor.Format);
-
- imageBindings[index] = new TextureBindingInfo(
- target,
- format,
- descriptor.Binding,
- descriptor.CbufSlot,
- descriptor.HandleIndex,
- descriptor.Flags);
-
- if (descriptor.Binding > maxImageBinding)
- {
- maxImageBinding = descriptor.Binding;
- }
- }
-
- _channel.TextureManager.SetComputeMaxBindings(maxTextureBinding, maxImageBinding);
+ _channel.TextureManager.SetComputeBindings(cs.Bindings);
// Should never return false for mismatching spec state, since the shader was fetched above.
_channel.TextureManager.CommitComputeBindings(cs.SpecializationState);
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
index 8da5ea5ef1..fe7e0d09f0 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
@@ -1257,88 +1257,24 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
UpdateUserClipState();
}
+ UpdateShaderBindings(gs.Bindings);
+
for (int stageIndex = 0; stageIndex < Constants.ShaderStages; stageIndex++)
{
- UpdateStageBindings(stageIndex, gs.Shaders[stageIndex + 1]?.Info);
+ _currentProgramInfo[stageIndex] = gs.Shaders[stageIndex + 1]?.Info;
}
_context.Renderer.Pipeline.SetProgram(gs.HostProgram);
}
///
- /// Updates bindings consumed by the shader stage on the texture and buffer managers.
+ /// Updates bindings consumed by the shader on the texture and buffer managers.
///
- /// Shader stage to have the bindings updated
- /// Shader stage bindings info
- private void UpdateStageBindings(int stage, ShaderProgramInfo info)
+ /// Bindings for the active shader
+ private void UpdateShaderBindings(CachedShaderBindings bindings)
{
- _currentProgramInfo[stage] = info;
-
- if (info == null)
- {
- _channel.TextureManager.RentGraphicsTextureBindings(stage, 0);
- _channel.TextureManager.RentGraphicsImageBindings(stage, 0);
- _channel.BufferManager.SetGraphicsStorageBufferBindings(stage, null);
- _channel.BufferManager.SetGraphicsUniformBufferBindings(stage, null);
- return;
- }
-
- int maxTextureBinding = -1;
- int maxImageBinding = -1;
-
- Span textureBindings = _channel.TextureManager.RentGraphicsTextureBindings(stage, info.Textures.Count);
-
- if (info.UsesRtLayer)
- {
- _vtgWritesRtLayer = true;
- }
-
- for (int index = 0; index < info.Textures.Count; index++)
- {
- var descriptor = info.Textures[index];
-
- Target target = ShaderTexture.GetTarget(descriptor.Type);
-
- textureBindings[index] = new TextureBindingInfo(
- target,
- descriptor.Binding,
- descriptor.CbufSlot,
- descriptor.HandleIndex,
- descriptor.Flags);
-
- if (descriptor.Binding > maxTextureBinding)
- {
- maxTextureBinding = descriptor.Binding;
- }
- }
-
- TextureBindingInfo[] imageBindings = _channel.TextureManager.RentGraphicsImageBindings(stage, info.Images.Count);
-
- for (int index = 0; index < info.Images.Count; index++)
- {
- var descriptor = info.Images[index];
-
- Target target = ShaderTexture.GetTarget(descriptor.Type);
- Format format = ShaderTexture.GetFormat(descriptor.Format);
-
- imageBindings[index] = new TextureBindingInfo(
- target,
- format,
- descriptor.Binding,
- descriptor.CbufSlot,
- descriptor.HandleIndex,
- descriptor.Flags);
-
- if (descriptor.Binding > maxImageBinding)
- {
- maxImageBinding = descriptor.Binding;
- }
- }
-
- _channel.TextureManager.SetGraphicsMaxBindings(maxTextureBinding, maxImageBinding);
-
- _channel.BufferManager.SetGraphicsStorageBufferBindings(stage, info.SBuffers);
- _channel.BufferManager.SetGraphicsUniformBufferBindings(stage, info.CBuffers);
+ _channel.TextureManager.SetGraphicsBindings(bindings);
+ _channel.BufferManager.SetGraphicsBufferBindings(bindings);
}
///
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
index 892d9f6a78..0787ce3d50 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
@@ -37,8 +37,8 @@ namespace Ryujinx.Graphics.Gpu.Image
private TexturePool _cachedTexturePool;
private SamplerPool _cachedSamplerPool;
- private readonly TextureBindingInfo[][] _textureBindings;
- private readonly TextureBindingInfo[][] _imageBindings;
+ private TextureBindingInfo[][] _textureBindings;
+ private TextureBindingInfo[][] _imageBindings;
private struct TextureState
{
@@ -56,9 +56,6 @@ namespace Ryujinx.Graphics.Gpu.Image
private TextureState[] _textureState;
private TextureState[] _imageState;
- private int[] _textureBindingsCount;
- private int[] _imageBindingsCount;
-
private int _texturePoolSequence;
private int _samplerPoolSequence;
@@ -101,9 +98,6 @@ namespace Ryujinx.Graphics.Gpu.Image
_textureState = new TextureState[InitialTextureStateSize];
_imageState = new TextureState[InitialImageStateSize];
- _textureBindingsCount = new int[stages];
- _imageBindingsCount = new int[stages];
-
for (int stage = 0; stage < stages; stage++)
{
_textureBindings[stage] = new TextureBindingInfo[InitialTextureStateSize];
@@ -112,39 +106,15 @@ namespace Ryujinx.Graphics.Gpu.Image
}
///
- /// Rents the texture bindings array for a given stage, so that they can be modified.
+ /// Sets the texture and image bindings.
///
- /// Shader stage number, or 0 for compute shaders
- /// The number of bindings needed
- /// The texture bindings array
- public TextureBindingInfo[] RentTextureBindings(int stage, int count)
+ /// Bindings for the active shader
+ public void SetBindings(CachedShaderBindings bindings)
{
- if (count > _textureBindings[stage].Length)
- {
- Array.Resize(ref _textureBindings[stage], count);
- }
+ _textureBindings = bindings.TextureBindings;
+ _imageBindings = bindings.ImageBindings;
- _textureBindingsCount[stage] = count;
-
- return _textureBindings[stage];
- }
-
- ///
- /// Rents the image bindings array for a given stage, so that they can be modified.
- ///
- /// Shader stage number, or 0 for compute shaders
- /// The number of bindings needed
- /// The image bindings array
- public TextureBindingInfo[] RentImageBindings(int stage, int count)
- {
- if (count > _imageBindings[stage].Length)
- {
- Array.Resize(ref _imageBindings[stage], count);
- }
-
- _imageBindingsCount[stage] = count;
-
- return _imageBindings[stage];
+ SetMaxBindings(bindings.MaxTextureBinding, bindings.MaxImageBinding);
}
///
@@ -257,7 +227,7 @@ namespace Ryujinx.Graphics.Gpu.Image
case ShaderStage.Vertex:
int fragmentIndex = (int)ShaderStage.Fragment - 1;
- index += _textureBindingsCount[fragmentIndex] + _imageBindingsCount[fragmentIndex];
+ index += _textureBindings[fragmentIndex].Length + _imageBindings[fragmentIndex].Length;
result = texture.ScaleFactor;
break;
@@ -284,7 +254,7 @@ namespace Ryujinx.Graphics.Gpu.Image
///
private bool VertexRequiresScale()
{
- for (int i = 0; i < _textureBindingsCount[0]; i++)
+ for (int i = 0; i < _textureBindings[0].Length; i++)
{
if ((_textureBindings[0][i].Flags & TextureUsageFlags.NeedsScaleValue) != 0)
{
@@ -292,7 +262,7 @@ namespace Ryujinx.Graphics.Gpu.Image
}
}
- for (int i = 0; i < _imageBindingsCount[0]; i++)
+ for (int i = 0; i < _imageBindings[0].Length; i++)
{
if ((_imageBindings[0][i].Flags & TextureUsageFlags.NeedsScaleValue) != 0)
{
@@ -309,10 +279,10 @@ namespace Ryujinx.Graphics.Gpu.Image
private void CommitRenderScale()
{
// Stage 0 total: Compute or Vertex.
- int total = _textureBindingsCount[0] + _imageBindingsCount[0];
+ int total = _textureBindings[0].Length + _imageBindings[0].Length;
int fragmentIndex = (int)ShaderStage.Fragment - 1;
- int fragmentTotal = _isCompute ? 0 : (_textureBindingsCount[fragmentIndex] + _imageBindingsCount[fragmentIndex]);
+ int fragmentTotal = _isCompute ? 0 : (_textureBindings[fragmentIndex].Length + _imageBindings[fragmentIndex].Length);
if (total != 0 && fragmentTotal != _lastFragmentTotal && VertexRequiresScale())
{
@@ -481,7 +451,7 @@ namespace Ryujinx.Graphics.Gpu.Image
bool poolModified,
ShaderSpecializationState specState)
{
- int textureCount = _textureBindingsCount[stageIndex];
+ int textureCount = _textureBindings[stageIndex].Length;
if (textureCount == 0)
{
return true;
@@ -609,7 +579,7 @@ namespace Ryujinx.Graphics.Gpu.Image
/// True if all bound images match the current shader specialiation state, false otherwise
private bool CommitImageBindings(TexturePool pool, ShaderStage stage, int stageIndex, bool poolModified, ShaderSpecializationState specState)
{
- int imageCount = _imageBindingsCount[stageIndex];
+ int imageCount = _imageBindings[stageIndex].Length;
if (imageCount == 0)
{
return true;
@@ -622,7 +592,7 @@ namespace Ryujinx.Graphics.Gpu.Image
}
// Scales for images appear after the texture ones.
- int baseScaleIndex = _textureBindingsCount[stageIndex];
+ int baseScaleIndex = _textureBindings[stageIndex].Length;
int cachedTextureBufferIndex = -1;
int cachedSamplerBufferIndex = -1;
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
index fe0175a6a6..083de64c55 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
@@ -57,45 +57,21 @@ namespace Ryujinx.Graphics.Gpu.Image
}
///
- /// Rents the texture bindings array of the compute pipeline.
+ /// Sets the texture and image bindings for the compute pipeline.
///
- /// The number of bindings needed
- /// The texture bindings array
- public TextureBindingInfo[] RentComputeTextureBindings(int count)
+ /// Bindings for the active shader
+ public void SetComputeBindings(CachedShaderBindings bindings)
{
- return _cpBindingsManager.RentTextureBindings(0, count);
+ _cpBindingsManager.SetBindings(bindings);
}
///
- /// Rents the texture bindings array for a given stage on the graphics pipeline.
+ /// Sets the texture and image bindings for the graphics pipeline.
///
- /// The index of the shader stage to bind the textures
- /// The number of bindings needed
- /// The texture bindings array
- public TextureBindingInfo[] RentGraphicsTextureBindings(int stage, int count)
+ /// Bindings for the active shader
+ public void SetGraphicsBindings(CachedShaderBindings bindings)
{
- return _gpBindingsManager.RentTextureBindings(stage, count);
- }
-
- ///
- /// Rents the image bindings array of the compute pipeline.
- ///
- /// The number of bindings needed
- /// The image bindings array
- public TextureBindingInfo[] RentComputeImageBindings(int count)
- {
- return _cpBindingsManager.RentImageBindings(0, count);
- }
-
- ///
- /// Rents the image bindings array for a given stage on the graphics pipeline.
- ///
- /// The index of the shader stage to bind the images
- /// The number of bindings needed
- /// The image bindings array
- public TextureBindingInfo[] RentGraphicsImageBindings(int stage, int count)
- {
- return _gpBindingsManager.RentImageBindings(stage, count);
+ _gpBindingsManager.SetBindings(bindings);
}
///
@@ -107,16 +83,6 @@ namespace Ryujinx.Graphics.Gpu.Image
_cpBindingsManager.SetTextureBufferIndex(index);
}
- ///
- /// Sets the max binding indexes on the compute pipeline.
- ///
- /// The maximum texture binding
- /// The maximum image binding
- public void SetComputeMaxBindings(int maxTextureBinding, int maxImageBinding)
- {
- _cpBindingsManager.SetMaxBindings(maxTextureBinding, maxImageBinding);
- }
-
///
/// Sets the texture constant buffer index on the graphics pipeline.
///
@@ -126,16 +92,6 @@ namespace Ryujinx.Graphics.Gpu.Image
_gpBindingsManager.SetTextureBufferIndex(index);
}
- ///
- /// Sets the max binding indexes on the graphics pipeline.
- ///
- /// The maximum texture binding
- /// The maximum image binding
- public void SetGraphicsMaxBindings(int maxTextureBinding, int maxImageBinding)
- {
- _gpBindingsManager.SetMaxBindings(maxTextureBinding, maxImageBinding);
- }
-
///
/// Sets the current sampler pool on the compute pipeline.
///
diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
index f0831e1582..1728cdb582 100644
--- a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
+++ b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
@@ -1,10 +1,10 @@
using Ryujinx.Common;
using Ryujinx.Graphics.GAL;
using Ryujinx.Graphics.Gpu.Image;
+using Ryujinx.Graphics.Gpu.Shader;
using Ryujinx.Graphics.Shader;
using System;
using System.Collections.Generic;
-using System.Collections.ObjectModel;
using System.Runtime.CompilerServices;
namespace Ryujinx.Graphics.Gpu.Memory
@@ -34,7 +34,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
///
/// Shader buffer binding information.
///
- public BufferDescriptor[] Bindings { get; }
+ public BufferDescriptor[] Bindings { get; private set; }
///
/// Buffer regions.
@@ -78,7 +78,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// Sets shader buffer binding information.
///
/// Buffer binding information
- public void SetBindings(ReadOnlyCollection descriptors)
+ public void SetBindings(BufferDescriptor[] descriptors)
{
if (descriptors == null)
{
@@ -86,8 +86,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
return;
}
- descriptors.CopyTo(Bindings, 0);
- Count = descriptors.Count;
+ if ((Count = descriptors.Length) != 0)
+ {
+ Bindings = descriptors;
+ }
}
}
@@ -320,41 +322,26 @@ namespace Ryujinx.Graphics.Gpu.Memory
///
/// Sets the binding points for the storage buffers bound on the compute pipeline.
///
- /// Buffer descriptors with the binding point values
- public void SetComputeStorageBufferBindings(ReadOnlyCollection descriptors)
+ /// Bindings for the active shader
+ public void SetComputeBufferBindings(CachedShaderBindings bindings)
{
- _cpStorageBuffers.SetBindings(descriptors);
+ _cpStorageBuffers.SetBindings(bindings.StorageBufferBindings[0]);
+ _cpUniformBuffers.SetBindings(bindings.ConstantBufferBindings[0]);
}
///
/// Sets the binding points for the storage buffers bound on the graphics pipeline.
///
- /// Index of the shader stage
- /// Buffer descriptors with the binding point values
- public void SetGraphicsStorageBufferBindings(int stage, ReadOnlyCollection descriptors)
+ /// Bindings for the active shader
+ public void SetGraphicsBufferBindings(CachedShaderBindings bindings)
{
- _gpStorageBuffers[stage].SetBindings(descriptors);
+ for (int i = 0; i < Constants.ShaderStages; i++)
+ {
+ _gpStorageBuffers[i].SetBindings(bindings.StorageBufferBindings[i]);
+ _gpUniformBuffers[i].SetBindings(bindings.ConstantBufferBindings[i]);
+ }
+
_gpStorageBuffersDirty = true;
- }
-
- ///
- /// Sets the binding points for the uniform buffers bound on the compute pipeline.
- ///
- /// Buffer descriptors with the binding point values
- public void SetComputeUniformBufferBindings(ReadOnlyCollection descriptors)
- {
- _cpUniformBuffers.SetBindings(descriptors);
- }
-
- ///
- /// Sets the enabled uniform buffers mask on the graphics pipeline.
- /// Each bit set on the mask indicates that the respective buffer index is enabled.
- ///
- /// Index of the shader stage
- /// Buffer descriptors with the binding point values
- public void SetGraphicsUniformBufferBindings(int stage, ReadOnlyCollection descriptors)
- {
- _gpUniformBuffers[stage].SetBindings(descriptors);
_gpUniformBuffersDirty = true;
}
diff --git a/Ryujinx.Graphics.Gpu/Shader/CachedShaderBindings.cs b/Ryujinx.Graphics.Gpu/Shader/CachedShaderBindings.cs
new file mode 100644
index 0000000000..1734f08a22
--- /dev/null
+++ b/Ryujinx.Graphics.Gpu/Shader/CachedShaderBindings.cs
@@ -0,0 +1,103 @@
+using Ryujinx.Graphics.GAL;
+using Ryujinx.Graphics.Gpu.Engine;
+using Ryujinx.Graphics.Gpu.Image;
+using Ryujinx.Graphics.Shader;
+using System;
+using System.Linq;
+
+namespace Ryujinx.Graphics.Gpu.Shader
+{
+ ///
+ /// A collection of shader bindings ready for insertion into the buffer and texture managers.
+ ///
+ internal class CachedShaderBindings
+ {
+ public TextureBindingInfo[][] TextureBindings { get; }
+ public TextureBindingInfo[][] ImageBindings { get; }
+ public BufferDescriptor[][] ConstantBufferBindings { get; }
+ public BufferDescriptor[][] StorageBufferBindings { get; }
+
+ public int MaxTextureBinding { get; }
+ public int MaxImageBinding { get; }
+
+ ///
+ /// Create a new cached shader bindings collection.
+ ///
+ /// Whether the shader is for compute
+ /// The stages used by the shader
+ public CachedShaderBindings(bool isCompute, CachedShaderStage[] stages)
+ {
+ int stageCount = isCompute ? 1 : Constants.ShaderStages;
+
+ TextureBindings = new TextureBindingInfo[stageCount][];
+ ImageBindings = new TextureBindingInfo[stageCount][];
+ ConstantBufferBindings = new BufferDescriptor[stageCount][];
+ StorageBufferBindings = new BufferDescriptor[stageCount][];
+
+ int maxTextureBinding = -1;
+ int maxImageBinding = -1;
+ int offset = isCompute ? 0 : 1;
+
+ for (int i = 0; i < stageCount; i++)
+ {
+ CachedShaderStage stage = stages[i + offset];
+
+ if (stage == null)
+ {
+ TextureBindings[i] = Array.Empty();
+ ImageBindings[i] = Array.Empty();
+ ConstantBufferBindings[i] = Array.Empty();
+ StorageBufferBindings[i] = Array.Empty();
+
+ continue;
+ }
+
+ TextureBindings[i] = stage.Info.Textures.Select(descriptor =>
+ {
+ Target target = ShaderTexture.GetTarget(descriptor.Type);
+
+ var result = new TextureBindingInfo(
+ target,
+ descriptor.Binding,
+ descriptor.CbufSlot,
+ descriptor.HandleIndex,
+ descriptor.Flags);
+
+ if (descriptor.Binding > maxTextureBinding)
+ {
+ maxTextureBinding = descriptor.Binding;
+ }
+
+ return result;
+ }).ToArray();
+
+ ImageBindings[i] = stage.Info.Images.Select(descriptor =>
+ {
+ Target target = ShaderTexture.GetTarget(descriptor.Type);
+ Format format = ShaderTexture.GetFormat(descriptor.Format);
+
+ var result = new TextureBindingInfo(
+ target,
+ format,
+ descriptor.Binding,
+ descriptor.CbufSlot,
+ descriptor.HandleIndex,
+ descriptor.Flags);
+
+ if (descriptor.Binding > maxImageBinding)
+ {
+ maxImageBinding = descriptor.Binding;
+ }
+
+ return result;
+ }).ToArray();
+
+ ConstantBufferBindings[i] = stage.Info.CBuffers.ToArray();
+ StorageBufferBindings[i] = stage.Info.SBuffers.ToArray();
+ }
+
+ MaxTextureBinding = maxTextureBinding;
+ MaxImageBinding = maxImageBinding;
+ }
+ }
+}
diff --git a/Ryujinx.Graphics.Gpu/Shader/CachedShaderProgram.cs b/Ryujinx.Graphics.Gpu/Shader/CachedShaderProgram.cs
index 69fcb27804..ff9c39a197 100644
--- a/Ryujinx.Graphics.Gpu/Shader/CachedShaderProgram.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/CachedShaderProgram.cs
@@ -24,6 +24,11 @@ namespace Ryujinx.Graphics.Gpu.Shader
///
public CachedShaderStage[] Shaders { get; }
+ ///
+ /// Cached shader bindings, ready for placing into the bindings manager.
+ ///
+ public CachedShaderBindings Bindings { get; }
+
///
/// Creates a new instance of the shader bundle.
///
@@ -37,6 +42,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
Shaders = shaders;
SpecializationState.Prepare(shaders);
+ Bindings = new CachedShaderBindings(shaders.Length == 1, shaders);
}
///