aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2020-11-08 08:10:00 -0300
committerGitHub <noreply@github.com>2020-11-08 12:10:00 +0100
commit8d168574eb04ae1e7026ac2b058e3b184f068fae (patch)
tree6e0f79447276619af980055419874f5e99595b58
parent5561a3b95e9c980e3354366570e7896a213b95ae (diff)
Use explicit buffer and texture bindings on shaders (#1666)
* Use explicit buffer and texture bindings on shaders * More XML docs and other nits
-rw-r--r--Ryujinx.Graphics.GAL/IPipeline.cs10
-rw-r--r--Ryujinx.Graphics.GAL/IRenderer.cs2
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Compute.cs36
-rw-r--r--Ryujinx.Graphics.Gpu/Engine/Methods.cs32
-rw-r--r--Ryujinx.Graphics.Gpu/Image/TextureBindingInfo.cs28
-rw-r--r--Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs36
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/BufferBounds.cs22
-rw-r--r--Ryujinx.Graphics.Gpu/Memory/BufferManager.cs272
-rw-r--r--Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs31
-rw-r--r--Ryujinx.Graphics.OpenGL/Pipeline.cs88
-rw-r--r--Ryujinx.Graphics.OpenGL/Program.cs149
-rw-r--r--Ryujinx.Graphics.OpenGL/Renderer.cs4
-rw-r--r--Ryujinx.Graphics.OpenGL/Shader.cs31
-rw-r--r--Ryujinx.Graphics.Shader/BufferDescriptor.cs7
-rw-r--r--Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs153
-rw-r--r--Ryujinx.Graphics.Shader/IGpuAccessor.cs30
-rw-r--r--Ryujinx.Graphics.Shader/TextureDescriptor.cs10
-rw-r--r--Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs8
-rw-r--r--Ryujinx.Graphics.Shader/Translation/TranslationCounts.cs30
-rw-r--r--Ryujinx.Graphics.Shader/Translation/Translator.cs34
20 files changed, 479 insertions, 534 deletions
diff --git a/Ryujinx.Graphics.GAL/IPipeline.cs b/Ryujinx.Graphics.GAL/IPipeline.cs
index 3baf272f..1da34b96 100644
--- a/Ryujinx.Graphics.GAL/IPipeline.cs
+++ b/Ryujinx.Graphics.GAL/IPipeline.cs
@@ -46,7 +46,7 @@ namespace Ryujinx.Graphics.GAL
void SetIndexBuffer(BufferRange buffer, IndexType type);
- void SetImage(int index, ShaderStage stage, ITexture texture, Format imageFormat);
+ void SetImage(int binding, ITexture texture, Format imageFormat);
void SetLogicOpState(bool enable, LogicalOp op);
@@ -64,19 +64,19 @@ namespace Ryujinx.Graphics.GAL
void SetRenderTargetColorMasks(ReadOnlySpan<uint> componentMask);
void SetRenderTargets(ITexture[] colors, ITexture depthStencil);
- void SetSampler(int index, ShaderStage stage, ISampler sampler);
+ void SetSampler(int binding, ISampler sampler);
void SetScissorEnable(int index, bool enable);
void SetScissor(int index, int x, int y, int width, int height);
void SetStencilTest(StencilTestDescriptor stencilTest);
- void SetStorageBuffer(int index, ShaderStage stage, BufferRange buffer);
+ void SetStorageBuffers(ReadOnlySpan<BufferRange> buffers);
- void SetTexture(int index, ShaderStage stage, ITexture texture);
+ void SetTexture(int binding, ITexture texture);
void SetTransformFeedbackBuffers(ReadOnlySpan<BufferRange> buffers);
- void SetUniformBuffer(int index, ShaderStage stage, BufferRange buffer);
+ void SetUniformBuffers(ReadOnlySpan<BufferRange> buffers);
void SetUserClipDistance(int index, bool enableClip);
diff --git a/Ryujinx.Graphics.GAL/IRenderer.cs b/Ryujinx.Graphics.GAL/IRenderer.cs
index 9fc39b4b..35c2146f 100644
--- a/Ryujinx.Graphics.GAL/IRenderer.cs
+++ b/Ryujinx.Graphics.GAL/IRenderer.cs
@@ -12,7 +12,7 @@ namespace Ryujinx.Graphics.GAL
void BackgroundContextAction(Action action);
- IShader CompileShader(ShaderProgram shader);
+ IShader CompileShader(ShaderStage stage, string code);
BufferHandle CreateBuffer(int size);
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();
diff --git a/Ryujinx.Graphics.OpenGL/Pipeline.cs b/Ryujinx.Graphics.OpenGL/Pipeline.cs
index 06cf5ef4..56873291 100644
--- a/Ryujinx.Graphics.OpenGL/Pipeline.cs
+++ b/Ryujinx.Graphics.OpenGL/Pipeline.cs
@@ -697,20 +697,20 @@ namespace Ryujinx.Graphics.OpenGL
SetFrontFace(_frontFace = frontFace.Convert());
}
- public void SetImage(int index, ShaderStage stage, ITexture texture, Format imageFormat)
+ public void SetImage(int binding, ITexture texture, Format imageFormat)
{
- int unit = _program.GetImageUnit(stage, index);
-
- if (unit != -1 && texture != null)
+ if (texture == null)
{
- TextureBase texBase = (TextureBase)texture;
+ return;
+ }
- SizedInternalFormat format = FormatTable.GetImageFormat(imageFormat);
+ TextureBase texBase = (TextureBase)texture;
- if (format != 0)
- {
- GL.BindImageTexture(unit, texBase.Handle, 0, true, 0, TextureAccess.ReadWrite, format);
- }
+ SizedInternalFormat format = FormatTable.GetImageFormat(imageFormat);
+
+ if (format != 0)
+ {
+ GL.BindImageTexture(binding, texBase.Handle, 0, true, 0, TextureAccess.ReadWrite, format);
}
}
@@ -866,14 +866,14 @@ namespace Ryujinx.Graphics.OpenGL
UpdateDepthTest();
}
- public void SetSampler(int index, ShaderStage stage, ISampler sampler)
+ public void SetSampler(int binding, ISampler sampler)
{
- int unit = _program.GetTextureUnit(stage, index);
-
- if (unit != -1 && sampler != null)
+ if (sampler == null)
{
- ((Sampler)sampler).Bind(unit);
+ return;
}
+
+ ((Sampler)sampler).Bind(binding);
}
public void SetScissorEnable(int index, bool enable)
@@ -939,25 +939,25 @@ namespace Ryujinx.Graphics.OpenGL
_stencilFrontMask = stencilTest.FrontMask;
}
- public void SetStorageBuffer(int index, ShaderStage stage, BufferRange buffer)
+ public void SetStorageBuffers(ReadOnlySpan<BufferRange> buffers)
{
- SetBuffer(index, stage, buffer, isStorage: true);
+ SetBuffers(buffers, isStorage: true);
}
- public void SetTexture(int index, ShaderStage stage, ITexture texture)
+ public void SetTexture(int binding, ITexture texture)
{
- int unit = _program.GetTextureUnit(stage, index);
+ if (texture == null)
+ {
+ return;
+ }
- if (unit != -1 && texture != null)
+ if (binding == 0)
{
- if (unit == 0)
- {
- _unit0Texture = (TextureBase)texture;
- }
- else
- {
- ((TextureBase)texture).Bind(unit);
- }
+ _unit0Texture = (TextureBase)texture;
+ }
+ else
+ {
+ ((TextureBase)texture).Bind(binding);
}
}
@@ -997,9 +997,9 @@ namespace Ryujinx.Graphics.OpenGL
}
}
- public void SetUniformBuffer(int index, ShaderStage stage, BufferRange buffer)
+ public void SetUniformBuffers(ReadOnlySpan<BufferRange> buffers)
{
- SetBuffer(index, stage, buffer, isStorage: false);
+ SetBuffers(buffers, isStorage: false);
}
public void SetUserClipDistance(int index, bool enableClip)
@@ -1077,30 +1077,22 @@ namespace Ryujinx.Graphics.OpenGL
GL.MemoryBarrier(MemoryBarrierFlags.TextureFetchBarrierBit);
}
- private void SetBuffer(int index, ShaderStage stage, BufferRange buffer, bool isStorage)
+ private void SetBuffers(ReadOnlySpan<BufferRange> buffers, bool isStorage)
{
- int bindingPoint = isStorage
- ? _program.GetStorageBufferBindingPoint(stage, index)
- : _program.GetUniformBufferBindingPoint(stage, index);
+ BufferRangeTarget target = isStorage ? BufferRangeTarget.ShaderStorageBuffer : BufferRangeTarget.UniformBuffer;
- if (bindingPoint == -1)
+ for (int index = 0; index < buffers.Length; index++)
{
- return;
- }
+ BufferRange buffer = buffers[index];
- BufferRangeTarget target = isStorage
- ? BufferRangeTarget.ShaderStorageBuffer
- : BufferRangeTarget.UniformBuffer;
+ if (buffer.Handle == BufferHandle.Null)
+ {
+ GL.BindBufferRange(target, index, 0, IntPtr.Zero, 0);
+ continue;
+ }
- if (buffer.Handle == BufferHandle.Null)
- {
- GL.BindBufferRange(target, bindingPoint, 0, IntPtr.Zero, 0);
- return;
+ GL.BindBufferRange(target, index, buffer.Handle.ToInt32(), (IntPtr)buffer.Offset, buffer.Size);
}
-
- IntPtr bufferOffset = (IntPtr)buffer.Offset;
-
- GL.BindBufferRange(target, bindingPoint, buffer.Handle.ToInt32(), bufferOffset, buffer.Size);
}
private void SetOrigin(ClipOrigin origin)
diff --git a/Ryujinx.Graphics.OpenGL/Program.cs b/Ryujinx.Graphics.OpenGL/Program.cs
index babe17a0..17e14df6 100644
--- a/Ryujinx.Graphics.OpenGL/Program.cs
+++ b/Ryujinx.Graphics.OpenGL/Program.cs
@@ -1,7 +1,6 @@
using OpenTK.Graphics.OpenGL;
using Ryujinx.Common.Logging;
using Ryujinx.Graphics.GAL;
-using Ryujinx.Graphics.Shader;
using Ryujinx.Graphics.Shader.CodeGen.Glsl;
using System;
using System.Collections.Generic;
@@ -11,18 +10,6 @@ namespace Ryujinx.Graphics.OpenGL
{
class Program : IProgram
{
- private const int ShaderStages = 6;
-
- private const int UbStageShift = 5;
- private const int SbStageShift = 4;
- private const int TexStageShift = 5;
- private const int ImgStageShift = 3;
-
- private const int UbsPerStage = 1 << UbStageShift;
- private const int SbsPerStage = 1 << SbStageShift;
- private const int TexsPerStage = 1 << TexStageShift;
- private const int ImgsPerStage = 1 << ImgStageShift;
-
public int Handle { get; private set; }
public int FragmentIsBgraUniform { get; }
@@ -31,38 +18,8 @@ namespace Ryujinx.Graphics.OpenGL
public bool IsLinked { get; private set; }
- private int[] _ubBindingPoints;
- private int[] _sbBindingPoints;
- private int[] _textureUnits;
- private int[] _imageUnits;
-
public Program(IShader[] shaders, TransformFeedbackDescriptor[] transformFeedbackDescriptors)
{
- _ubBindingPoints = new int[UbsPerStage * ShaderStages];
- _sbBindingPoints = new int[SbsPerStage * ShaderStages];
- _textureUnits = new int[TexsPerStage * ShaderStages];
- _imageUnits = new int[ImgsPerStage * ShaderStages];
-
- for (int index = 0; index < _ubBindingPoints.Length; index++)
- {
- _ubBindingPoints[index] = -1;
- }
-
- for (int index = 0; index < _sbBindingPoints.Length; index++)
- {
- _sbBindingPoints[index] = -1;
- }
-
- for (int index = 0; index < _textureUnits.Length; index++)
- {
- _textureUnits[index] = -1;
- }
-
- for (int index = 0; index < _imageUnits.Length; index++)
- {
- _imageUnits[index] = -1;
- }
-
Handle = GL.CreateProgram();
for (int index = 0; index < shaders.Length; index++)
@@ -131,92 +88,6 @@ namespace Ryujinx.Graphics.OpenGL
CheckProgramLink();
- int ubBindingPoint = 0;
- int sbBindingPoint = 0;
- int textureUnit = 0;
- int imageUnit = 0;
-
- for (int index = 0; index < shaders.Length; index++)
- {
- Shader shader = (Shader)shaders[index];
-
- foreach (BufferDescriptor descriptor in shader.Info.CBuffers)
- {
- int location = GL.GetUniformBlockIndex(Handle, descriptor.Name);
-
- if (location < 0)
- {
- continue;
- }
-
- GL.UniformBlockBinding(Handle, location, ubBindingPoint);
-
- int bpIndex = (int)shader.Stage << UbStageShift | descriptor.Slot;
-
- _ubBindingPoints[bpIndex] = ubBindingPoint;
-
- ubBindingPoint++;
- }
-
- foreach (BufferDescriptor descriptor in shader.Info.SBuffers)
- {
- int location = GL.GetProgramResourceIndex(Handle, ProgramInterface.ShaderStorageBlock, descriptor.Name);
-
- if (location < 0)
- {
- continue;
- }
-
- GL.ShaderStorageBlockBinding(Handle, location, sbBindingPoint);
-
- int bpIndex = (int)shader.Stage << SbStageShift | descriptor.Slot;
-
- _sbBindingPoints[bpIndex] = sbBindingPoint;
-
- sbBindingPoint++;
- }
-
- int samplerIndex = 0;
-
- foreach (TextureDescriptor descriptor in shader.Info.Textures)
- {
- int location = GL.GetUniformLocation(Handle, descriptor.Name);
-
- if (location < 0)
- {
- continue;
- }
-
- GL.ProgramUniform1(Handle, location, textureUnit);
-
- int uIndex = (int)shader.Stage << TexStageShift | samplerIndex++;
-
- _textureUnits[uIndex] = textureUnit;
-
- textureUnit++;
- }
-
- int imageIndex = 0;
-
- foreach (TextureDescriptor descriptor in shader.Info.Images)
- {
- int location = GL.GetUniformLocation(Handle, descriptor.Name);
-
- if (location < 0)
- {
- continue;
- }
-
- GL.ProgramUniform1(Handle, location, imageUnit);
-
- int uIndex = (int)shader.Stage << ImgStageShift | imageIndex++;
-
- _imageUnits[uIndex] = imageUnit;
-
- imageUnit++;
- }
- }
-
FragmentIsBgraUniform = GL.GetUniformLocation(Handle, "is_bgra");
FragmentRenderScaleUniform = GL.GetUniformLocation(Handle, "fp_renderScale");
ComputeRenderScaleUniform = GL.GetUniformLocation(Handle, "cp_renderScale");
@@ -227,26 +98,6 @@ namespace Ryujinx.Graphics.OpenGL
GL.UseProgram(Handle);
}
- public int GetUniformBufferBindingPoint(ShaderStage stage, int index)
- {
- return _ubBindingPoints[(int)stage << UbStageShift | index];
- }
-
- public int GetStorageBufferBindingPoint(ShaderStage stage, int index)
- {
- return _sbBindingPoints[(int)stage << SbStageShift | index];
- }
-
- public int GetTextureUnit(ShaderStage stage, int index)
- {
- return _textureUnits[(int)stage << TexStageShift | index];
- }
-
- public int GetImageUnit(ShaderStage stage, int index)
- {
- return _imageUnits[(int)stage << ImgStageShift | index];
- }
-
private void CheckProgramLink()
{
GL.GetProgram(Handle, GetProgramParameterName.LinkStatus, out int status);
diff --git a/Ryujinx.Graphics.OpenGL/Renderer.cs b/Ryujinx.Graphics.OpenGL/Renderer.cs
index aac3c69e..75bcda12 100644
--- a/Ryujinx.Graphics.OpenGL/Renderer.cs
+++ b/Ryujinx.Graphics.OpenGL/Renderer.cs
@@ -42,9 +42,9 @@ namespace Ryujinx.Graphics.OpenGL
ResourcePool = new ResourcePool();
}
- public IShader CompileShader(ShaderProgram shader)
+ public IShader CompileShader(ShaderStage stage, string code)
{
- return new Shader(shader);
+ return new Shader(stage, code);
}
public BufferHandle CreateBuffer(int size)
diff --git a/Ryujinx.Graphics.OpenGL/Shader.cs b/Ryujinx.Graphics.OpenGL/Shader.cs
index f25845cf..1df07ee4 100644
--- a/Ryujinx.Graphics.OpenGL/Shader.cs
+++ b/Ryujinx.Graphics.OpenGL/Shader.cs
@@ -8,31 +8,22 @@ namespace Ryujinx.Graphics.OpenGL
{
public int Handle { get; private set; }
- private ShaderProgram _program;
-
- public ShaderProgramInfo Info => _program.Info;
-
- public ShaderStage Stage => _program.Stage;
-
- public Shader(ShaderProgram program)
+ public Shader(ShaderStage stage, string code)
{
- _program = program;
-
- ShaderType type = ShaderType.VertexShader;
-
- switch (program.Stage)
+ ShaderType type = stage switch
{
- case ShaderStage.Compute: type = ShaderType.ComputeShader; break;
- case ShaderStage.Vertex: type = ShaderType.VertexShader; break;
- case ShaderStage.TessellationControl: type = ShaderType.TessControlShader; break;
- case ShaderStage.TessellationEvaluation: type = ShaderType.TessEvaluationShader; break;
- case ShaderStage.Geometry: type = ShaderType.GeometryShader; break;
- case ShaderStage.Fragment: type = ShaderType.FragmentShader; break;
- }
+ ShaderStage.Compute => ShaderType.ComputeShader,
+ ShaderStage.Vertex => ShaderType.VertexShader,
+ ShaderStage.TessellationControl => ShaderType.TessControlShader,
+ ShaderStage.TessellationEvaluation => ShaderType.TessEvaluationShader,
+ ShaderStage.Geometry => ShaderType.GeometryShader,
+ ShaderStage.Fragment => ShaderType.FragmentShader,
+ _ => ShaderType.VertexShader
+ };
Handle = GL.CreateShader(type);
- GL.ShaderSource(Handle, program.Code);
+ GL.ShaderSource(Handle, code);
GL.CompileShader(Handle);
}
diff --git a/Ryujinx.Graphics.Shader/BufferDescriptor.cs b/Ryujinx.Graphics.Shader/BufferDescriptor.cs
index 4cc99998..99855518 100644
--- a/Ryujinx.Graphics.Shader/BufferDescriptor.cs
+++ b/Ryujinx.Graphics.Shader/BufferDescriptor.cs
@@ -2,13 +2,12 @@ namespace Ryujinx.Graphics.Shader
{
public struct BufferDescriptor
{
- public string Name { get; }
-
+ public int Binding { get; }
public int Slot { get; }
- public BufferDescriptor(string name, int slot)
+ public BufferDescriptor(int binding, int slot)
{
- Name = name;
+ Binding = binding;
Slot = slot;
}
}
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
index 734546a0..56a01264 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Declarations.cs
@@ -218,50 +218,46 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
if (info.UsesCbIndexing)
{
- string ubName = OperandManager.GetShaderStagePrefix(context.Config.Stage);
+ int count = info.CBuffers.Max() + 1;
- ubName += "_" + DefaultNames.UniformNamePrefix;
+ int[] bindings = new int[count];
- string blockName = $"{ubName}_{DefaultNames.BlockSuffix}";
-
- int maxSlot = 0;
+ for (int i = 0; i < count; i++)
+ {
+ bindings[i] = context.Config.Counts.IncrementUniformBuffersCount();
+ }
foreach (int cbufSlot in info.CBuffers.OrderBy(x => x))
{
- context.CBufferDescriptors.Add(new BufferDescriptor($"{blockName}[{cbufSlot}]", cbufSlot));
-
- if (maxSlot < cbufSlot)
- {
- maxSlot = cbufSlot;
- }
+ context.CBufferDescriptors.Add(new BufferDescriptor(bindings[cbufSlot], cbufSlot));
}
- context.AppendLine("layout (std140) uniform " + blockName);
-
- context.EnterScope();
+ string ubName = OperandManager.GetShaderStagePrefix(context.Config.Stage);
- context.AppendLine("vec4 " + DefaultNames.DataName + ubSize + ";");
+ ubName += "_" + DefaultNames.UniformNamePrefix;
- string arraySize = NumberFormatter.FormatInt(maxSlot + 1);
+ string blockName = $"{ubName}_{DefaultNames.BlockSuffix}";
- context.LeaveScope($" {ubName}[{arraySize}];");
+ context.AppendLine($"layout (binding = {bindings[0]}, std140) uniform {blockName}");
+ context.EnterScope();
+ context.AppendLine("vec4 " + DefaultNames.DataName + ubSize + ";");
+ context.LeaveScope($" {ubName}[{NumberFormatter.FormatInt(count)}];");
}
else
{
foreach (int cbufSlot in info.CBuffers.OrderBy(x => x))
{
- string ubName = OperandManager.GetShaderStagePrefix(context.Config.Stage);
+ int binding = context.Config.Counts.IncrementUniformBuffersCount();
- ubName += "_" + DefaultNames.UniformNamePrefix + cbufSlot;
+ context.CBufferDescriptors.Add(new BufferDescriptor(binding, cbufSlot));
- context.CBufferDescriptors.Add(new BufferDescriptor(ubName, cbufSlot));
+ string ubName = OperandManager.GetShaderStagePrefix(context.Config.Stage);
- context.AppendLine("layout (std140) uniform " + ubName);
+ ubName += "_" + DefaultNames.UniformNamePrefix + cbufSlot;
+ context.AppendLine($"layout (binding = {binding}, std140) uniform {ubName}");
context.EnterScope();
-
context.AppendLine("vec4 " + OperandManager.GetUbName(context.Config.Stage, cbufSlot, false) + ubSize + ";");
-
context.LeaveScope(";");
}
}
@@ -275,32 +271,29 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
string blockName = $"{sbName}_{DefaultNames.BlockSuffix}";
- int maxSlot = 0;
+ int count = info.SBuffers.Max() + 1;
- foreach (int sbufSlot in info.SBuffers)
- {
- context.SBufferDescriptors.Add(new BufferDescriptor($"{blockName}[{sbufSlot}]", sbufSlot));
+ int[] bindings = new int[count];
- if (maxSlot < sbufSlot)
- {
- maxSlot = sbufSlot;
- }
+ for (int i = 0; i < count; i++)
+ {
+ bindings[i] = context.Config.Counts.IncrementStorageBuffersCount();
}
- context.AppendLine("layout (std430) buffer " + blockName);
+ foreach (int sbufSlot in info.SBuffers)
+ {
+ context.SBufferDescriptors.Add(new BufferDescriptor(bindings[sbufSlot], sbufSlot));
+ }
+ context.AppendLine($"layout (binding = {bindings[0]}, std430) buffer {blockName}");
context.EnterScope();
-
context.AppendLine("uint " + DefaultNames.DataName + "[];");
-
- string arraySize = NumberFormatter.FormatInt(maxSlot + 1);
-
- context.LeaveScope($" {sbName}[{arraySize}];");
+ context.LeaveScope($" {sbName}[{NumberFormatter.FormatInt(count)}];");
}
private static void DeclareSamplers(CodeGenContext context, StructuredProgramInfo info)
{
- Dictionary<string, AstTextureOperation> samplers = new Dictionary<string, AstTextureOperation>();
+ HashSet<string> samplers = new HashSet<string>();
// Texture instructions other than TextureSample (like TextureSize)
// may have incomplete sampler type information. In those cases,
@@ -312,29 +305,20 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
string samplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
- if (!samplers.TryAdd(samplerName, texOp))
+ if (!samplers.Add(samplerName))
{
continue;
}
- string samplerTypeName = texOp.Type.ToGlslSamplerType();
-
- context.AppendLine("uniform " + samplerTypeName + " " + samplerName + ";");
- }
-
- foreach (KeyValuePair<string, AstTextureOperation> kv in samplers)
- {
- string samplerName = kv.Key;
-
- AstTextureOperation texOp = kv.Value;
-
- TextureDescriptor desc;
+ int firstBinding = -1;
if ((texOp.Flags & TextureFlags.Bindless) != 0)
{
AstOperand operand = texOp.GetSource(0) as AstOperand;
- desc = new TextureDescriptor(samplerName, texOp.Type, operand.CbufSlot, operand.CbufOffset);
+ firstBinding = context.Config.Counts.IncrementTexturesCount();
+
+ var desc = new TextureDescriptor(firstBinding, texOp.Type, operand.CbufSlot, operand.CbufOffset);
context.TextureDescriptors.Add(desc);
}
@@ -342,27 +326,36 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
{
for (int index = 0; index < texOp.ArraySize; index++)
{
- string indexExpr = NumberFormatter.FormatInt(index);
+ int binding = context.Config.Counts.IncrementTexturesCount();
- string indexedSamplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
+ if (firstBinding < 0)
+ {
+ firstBinding = binding;
+ }
- desc = new TextureDescriptor(indexedSamplerName, texOp.Type, texOp.Format, texOp.Handle + index * 2);
+ var desc = new TextureDescriptor(binding, texOp.Type, texOp.Format, texOp.Handle + index * 2);
context.TextureDescriptors.Add(desc);
}
}
else
{
- desc = new TextureDescriptor(samplerName, texOp.Type, texOp.Format, texOp.Handle);
+ firstBinding = context.Config.Counts.IncrementTexturesCount();
+
+ var desc = new TextureDescriptor(firstBinding, texOp.Type, texOp.Format, texOp.Handle);
context.TextureDescriptors.Add(desc);
}
+
+ string samplerTypeName = texOp.Type.ToGlslSamplerType();
+
+ context.AppendLine($"layout (binding = {firstBinding}) uniform {samplerTypeName} {samplerName};");
}
}
private static void DeclareImages(CodeGenContext context, StructuredProgramInfo info)
{
- Dictionary<string, AstTextureOperation> images = new Dictionary<string, AstTextureOperation>();
+ HashSet<string> images = new HashSet<string>();
foreach (AstTextureOperation texOp in info.Images.OrderBy(x => x.Handle))
{
@@ -370,48 +363,48 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl
string imageName = OperandManager.GetImageName(context.Config.Stage, texOp, indexExpr);
- if (!images.TryAdd(imageName, texOp))
+ if (!images.Add(imageName))
{
continue;
}
- string layout = texOp.Format.ToGlslFormat();
-
- if (!string.IsNullOrEmpty(layout))
- {
- layout = "layout(" + layout + ") ";
- }
-
- string imageTypeName = texOp.Type.ToGlslImageType(texOp.Format.GetComponentType());
-
- context.AppendLine("uniform " + layout + imageTypeName + " " + imageName + ";");
- }
-
- foreach (KeyValuePair<string, AstTextureOperation> kv in images)
- {
- string imageName = kv.Key;
-
- AstTextureOperation texOp = kv.Value;
+ int firstBinding = -1;
if ((texOp.Type & SamplerType.Indexed) != 0)
{
for (int index = 0; index < texOp.ArraySize; index++)
{
- string indexExpr = NumberFormatter.FormatInt(index);
+ int binding = context.Config.Counts.IncrementImagesCount();
- string indexedSamplerName = OperandManager.GetSamplerName(context.Config.Stage, texOp, indexExpr);
+ if (firstBinding < 0)
+ {
+ firstBinding = binding;
+ }
- var desc = new TextureDescriptor(indexedSamplerName, texOp.Type, texOp.Format, texOp.Handle + index * 2);
+ var desc = new TextureDescriptor(binding, texOp.Type, texOp.Format, texOp.Handle + index * 2);
- context.TextureDescriptors.Add(desc);
+ context.ImageDescriptors.Add(desc);
}
}
else
{
- var desc = new TextureDescriptor(imageName, texOp.Type, texOp.Format, texOp.Handle);
+ firstBinding = context.Config.Counts.IncrementImagesCount();
+
+ var desc = new TextureDescriptor(firstBinding, texOp.Type, texOp.Format, texOp.Handle);
context.ImageDescriptors.Add(desc);
}
+
+ string layout = texOp.Format.ToGlslFormat();
+
+ if (!string.IsNullOrEmpty(layout))
+ {
+ layout = ", " + layout;
+ }
+
+ string imageTypeName = texOp.Type.ToGlslImageType(texOp.Format.GetComponentType());
+
+ context.AppendLine($"layout (binding = {firstBinding}{layout}) uniform {imageTypeName} {imageName};");
}
}
diff --git a/Ryujinx.Graphics.Shader/IGpuAccessor.cs b/Ryujinx.Graphics.Shader/IGpuAccessor.cs
index ea936c62..cb9db922 100644
--- a/Ryujinx.Graphics.Shader/IGpuAccessor.cs
+++ b/Ryujinx.Graphics.Shader/IGpuAccessor.cs
@@ -2,79 +2,79 @@
{
public interface IGpuAccessor
{
- public void Log(string message)
+ void Log(string message)
{
// No default log output.
}
T MemoryRead<T>(ulong address) where T : unmanaged;
- public bool MemoryMapped(ulong address)
+ bool MemoryMapped(ulong address)
{
return true;
}
- public int QueryComputeLocalSizeX()
+ int QueryComputeLocalSizeX()
{
return 1;
}
- public int QueryComputeLocalSizeY()
+ int QueryComputeLocalSizeY()
{
return 1;
}
- public int QueryComputeLocalSizeZ()
+ int QueryComputeLocalSizeZ()
{
return 1;
}
- public int QueryComputeLocalMemorySize()
+ int QueryComputeLocalMemorySize()
{
return 0x1000;
}
- public int QueryComputeSharedMemorySize()
+ int QueryComputeSharedMemorySize()
{
return 0xc000;
}
- public uint QueryConstantBufferUse()
+ uint QueryConstantBufferUse()
{
return 0xffff;
}
- public bool QueryIsTextureBuffer(int handle)
+ bool QueryIsTextureBuffer(int handle)
{
return false;
}
- public bool QueryIsTextureRectangle(int handle)
+ bool QueryIsTextureRectangle(int handle)
{
return false;
}
- public InputTopology QueryPrimitiveTopology()
+ InputTopology QueryPrimitiveTopology()
{
return InputTopology.Points;
}
- public int QueryStorageBufferOffsetAlignment()
+ int QueryStorageBufferOffsetAlignment()
{
return 16;
}
- public bool QuerySupportsImageLoadFormatted()
+ bool QuerySupportsImageLoadFormatted()
{
return true;
}
- public bool QuerySupportsNonConstantTextureOffset()
+ bool QuerySupportsNonConstantTextureOffset()
{
return true;
}
- public TextureFormat QueryTextureFormat(int handle)
+ TextureFormat QueryTextureFormat(int handle)
{
return TextureFormat.R8G8B8A8Unorm;
}
diff --git a/Ryujinx.Graphics.Shader/TextureDescriptor.cs b/Ryujinx.Graphics.Shader/TextureDescriptor.cs
index 7cf868ef..b39d6c3d 100644
--- a/Ryujinx.Graphics.Shader/TextureDescriptor.cs
+++ b/Ryujinx.Graphics.Shader/TextureDescriptor.cs
@@ -2,7 +2,7 @@ namespace Ryujinx.Graphics.Shader
{
public struct TextureDescriptor
{
- public string Name { get; }
+ public int Binding { get; }
public SamplerType Type { get; }
@@ -17,9 +17,9 @@ namespace Ryujinx.Graphics.Shader
public TextureUsageFlags Flags { get; set; }
- public TextureDescriptor(string name, SamplerType type, TextureFormat format, int handleIndex)
+ public TextureDescriptor(int binding, SamplerType type, TextureFormat format, int handleIndex)
{
- Name = name;
+ Binding = binding;
Type = type;
Format = format;
HandleIndex = handleIndex;
@@ -32,9 +32,9 @@ namespace Ryujinx.Graphics.Shader
Flags = TextureUsageFlags.None;
}
- public TextureDescriptor(string name, SamplerType type, int cbufSlot, int cbufOffset)
+ public TextureDescriptor(int binding, SamplerType type, int cbufSlot, int cbufOffset)
{
- Name = name;
+ Binding = binding;
Type = type;
Format = TextureFormat.Unknown;
HandleIndex = 0;
diff --git a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
index 7b1587ae..08e7df3b 100644
--- a/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
+++ b/Ryujinx.Graphics.Shader/Translation/ShaderConfig.cs
@@ -20,11 +20,13 @@ namespace Ryujinx.Graphics.Shader.Translation
public TranslationFlags Flags { get; }
+ public TranslationCounts Counts { get; }
+
public int Size { get; private set; }
public FeatureFlags UsedFeatures { get; private set; }
- public ShaderConfig(IGpuAccessor gpuAccessor, TranslationFlags flags)
+ public ShaderConfig(IGpuAccessor gpuAccessor, TranslationFlags flags, TranslationCounts counts)
{
Stage = ShaderStage.Compute;
OutputTopology = OutputTopology.PointList;
@@ -38,9 +40,10 @@ namespace Ryujinx.Graphics.Shader.Translation
Flags = flags;
Size = 0;
UsedFeatures = FeatureFlags.None;
+ Counts = counts;
}
- public ShaderConfig(ShaderHeader header, IGpuAccessor gpuAccessor, TranslationFlags flags)
+ public ShaderConfig(ShaderHeader header, IGpuAccessor gpuAccessor, TranslationFlags flags, TranslationCounts counts)
{
Stage = header.Stage;
OutputTopology = header.OutputTopology;
@@ -54,6 +57,7 @@ namespace Ryujinx.Graphics.Shader.Translation
Flags = flags;
Size = 0;
UsedFeatures = FeatureFlags.None;
+ Counts = counts;
}
public int GetDepthRegister()
diff --git a/Ryujinx.Graphics.Shader/Translation/TranslationCounts.cs b/Ryujinx.Graphics.Shader/Translation/TranslationCounts.cs
new file mode 100644
index 00000000..18f4725d
--- /dev/null
+++ b/Ryujinx.Graphics.Shader/Translation/TranslationCounts.cs
@@ -0,0 +1,30 @@
+namespace Ryujinx.Graphics.Shader.Translation
+{
+ public class TranslationCounts
+ {
+ public int UniformBuffersCount { get; private set; }
+ public int StorageBuffersCount { get; private set; }
+ public int TexturesCount { get; private set; }
+ public int ImagesCount { get; private set; }
+
+ internal int IncrementUniformBuffersCount()
+ {
+ return UniformBuffersCount++;
+ }
+
+ internal int IncrementStorageBuffersCount()
+ {
+ return StorageBuffersCount++;
+ }
+
+ internal int IncrementTexturesCount()
+ {
+ return TexturesCount++;
+ }
+
+ internal int IncrementImagesCount()
+ {
+ return ImagesCount++;
+ }
+ }
+}
diff --git a/Ryujinx.Graphics.Shader/Translation/Translator.cs b/Ryujinx.Graphics.Shader/Translation/Translator.cs
index f8093c84..f86b6964 100644
--- a/Ryujinx.Graphics.Shader/Translation/Translator.cs
+++ b/Ryujinx.Graphics.Shader/Translation/Translator.cs
@@ -24,15 +24,28 @@ namespace Ryujinx.Graphics.Shader.Translation
}
}
- public static ShaderProgram Translate(ulong address, IGpuAccessor gpuAccessor, TranslationFlags flags)
+ public static ShaderProgram Translate(
+ ulong address,
+ IGpuAccessor gpuAccessor,
+ TranslationFlags flags,
+ TranslationCounts counts = null)
{
- return Translate(DecodeShader(address, gpuAccessor, flags, out ShaderConfig config), config);
+ counts ??= new TranslationCounts();
+
+ return Translate(DecodeShader(address, gpuAccessor, flags, counts, out ShaderConfig config), config);
}
- public static ShaderProgram Translate(ulong addressA, ulong addressB, IGpuAccessor gpuAccessor, TranslationFlags flags)
+ public static ShaderProgram Translate(
+ ulong addressA,
+ ulong addressB,
+ IGpuAccessor gpuAccessor,
+ TranslationFlags flags,
+ TranslationCounts counts = null)
{
- FunctionCode[] funcA = DecodeShader(addressA, gpuAccessor, flags | TranslationFlags.VertexA, out ShaderConfig configA);
- FunctionCode[] funcB = DecodeShader(addressB, gpuAccessor, flags, out ShaderConfig config);
+ counts ??= new TranslationCounts();
+
+ FunctionCode[] funcA = DecodeShader(addressA, gpuAccessor, flags | TranslationFlags.VertexA, counts, out ShaderConfig configA);
+ FunctionCode[] funcB = DecodeShader(addressB, gpuAccessor, flags, counts, out ShaderConfig config);
config.SetUsedFeature(configA.UsedFeatures);
@@ -105,19 +118,24 @@ namespace Ryujinx.Graphics.Shader.Translation
return new ShaderProgram(spInfo, config.Stage, glslCode, config.Size, sizeA);
}
- private static FunctionCode[] DecodeShader(ulong address, IGpuAccessor gpuAccessor, TranslationFlags flags, out ShaderConfig config)
+ private static FunctionCode[] DecodeShader(
+ ulong address,
+ IGpuAccessor gpuAccessor,
+ TranslationFlags flags,
+ TranslationCounts counts,
+ out ShaderConfig config)
{
Block[][] cfg;
if ((flags & TranslationFlags.Compute) != 0)
{
- config = new ShaderConfig(gpuAccessor, flags);
+ config = new ShaderConfig(gpuAccessor, flags, counts);
cfg = Decoder.Decode(gpuAccessor, address);
}
else
{
- config = new ShaderConfig(new ShaderHeader(gpuAccessor, address), gpuAccessor, flags);
+ config = new ShaderConfig(new ShaderHeader(gpuAccessor, address), gpuAccessor, flags, counts);
cfg = Decoder.Decode(gpuAccessor, address + HeaderSize);
}