Use explicit buffer and texture bindings on shaders (#1666)
* Use explicit buffer and texture bindings on shaders * More XML docs and other nits
This commit is contained in:
parent
5561a3b95e
commit
8d168574eb
20 changed files with 496 additions and 551 deletions
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,11 @@ namespace Ryujinx.Graphics.Gpu.Image
|
|||
/// </summary>
|
||||
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.
|
||||
|
@ -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;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
|
@ -291,19 +365,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
return mask;
|
||||
}
|
||||
|
||||
/// <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>
|
||||
|
@ -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)
|
||||
ref var bindingInfo = ref _cpStorageBuffers.Bindings[index];
|
||||
|
||||
BufferBounds bounds = _cpStorageBuffers.Buffers[bindingInfo.Slot];
|
||||
|
||||
if (bounds.Address != 0)
|
||||
{
|
||||
continue;
|
||||
sRanges[bindingInfo.Binding] = GetBufferRange(bounds.Address, bounds.Size);
|
||||
}
|
||||
|
||||
BufferBounds bounds = _cpStorageBuffers.Buffers[index];
|
||||
|
||||
if (bounds.Address == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
BufferRange buffer = GetBufferRange(bounds.Address, bounds.Size);
|
||||
|
||||
_context.Renderer.Pipeline.SetStorageBuffer(index, ShaderStage.Compute, buffer);
|
||||
}
|
||||
|
||||
enableMask = _cpUniformBuffers.EnableMask;
|
||||
_context.Renderer.Pipeline.SetStorageBuffers(sRanges);
|
||||
|
||||
for (int index = 0; (enableMask >> index) != 0; index++)
|
||||
int uCount = _cpUniformBufferBindings;
|
||||
|
||||
Span<BufferRange> uRanges = uCount < StackToHeapThreshold ? stackalloc BufferRange[uCount] : new BufferRange[uCount];
|
||||
|
||||
for (int index = 0; index < _cpUniformBuffers.Count; index++)
|
||||
{
|
||||
if ((enableMask & (1u << index)) == 0)
|
||||
ref var bindingInfo = ref _cpUniformBuffers.Bindings[index];
|
||||
|
||||
BufferBounds bounds = _cpUniformBuffers.Buffers[bindingInfo.Slot];
|
||||
|
||||
if (bounds.Address != 0)
|
||||
{
|
||||
continue;
|
||||
uRanges[bindingInfo.Binding] = GetBufferRange(bounds.Address, bounds.Size);
|
||||
}
|
||||
|
||||
BufferBounds bounds = _cpUniformBuffers.Buffers[index];
|
||||
|
||||
if (bounds.Address == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
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>
|
||||
|
@ -659,74 +742,27 @@ namespace Ryujinx.Graphics.Gpu.Memory
|
|||
/// </summary>
|
||||
/// <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>
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue