Implement shader storage buffer operations using new Load/Store instructions (#4993)
* Implement storage buffer operations using new Load/Store instruction * Extend GenerateMultiTargetStorageOp to also match access with constant offset, and log and comments * Remove now unused code * Catch more complex cases of global memory usage * Shader cache version bump * Extend global access elimination to work with more shared memory cases * Change alignment requirement from 16 bytes to 8 bytes, handle cases where we need more than 16 storage buffers * Tweak preferencing to catch more cases * Enable CB0 elimination even when host storage buffer alignment is > 16 (for Intel) * Fix storage buffer bindings * Simplify some code * Shader cache version bump * Fix typo * Extend global memory elimination to handle shared memory with multiple possible offsets and local memory
This commit is contained in:
parent
81c9052847
commit
21c9ac6240
42 changed files with 1468 additions and 1259 deletions
|
@ -14,6 +14,11 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
private readonly string _stagePrefix;
|
||||
|
||||
private readonly int[] _cbSlotToBindingMap;
|
||||
private readonly int[] _sbSlotToBindingMap;
|
||||
private uint _sbSlotWritten;
|
||||
|
||||
private readonly Dictionary<int, int> _sbSlots;
|
||||
private readonly Dictionary<int, int> _sbSlotsReverse;
|
||||
|
||||
private readonly HashSet<int> _usedConstantBufferBindings;
|
||||
|
||||
|
@ -26,7 +31,12 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
_stagePrefix = GetShaderStagePrefix(stage);
|
||||
|
||||
_cbSlotToBindingMap = new int[18];
|
||||
_sbSlotToBindingMap = new int[16];
|
||||
_cbSlotToBindingMap.AsSpan().Fill(-1);
|
||||
_sbSlotToBindingMap.AsSpan().Fill(-1);
|
||||
|
||||
_sbSlots = new Dictionary<int, int>();
|
||||
_sbSlotsReverse = new Dictionary<int, int>();
|
||||
|
||||
_usedConstantBufferBindings = new HashSet<int>();
|
||||
|
||||
|
@ -47,6 +57,52 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
return binding;
|
||||
}
|
||||
|
||||
public bool TryGetStorageBufferBinding(int sbCbSlot, int sbCbOffset, bool write, out int binding)
|
||||
{
|
||||
if (!TryGetSbSlot((byte)sbCbSlot, (ushort)sbCbOffset, out int slot))
|
||||
{
|
||||
binding = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
binding = _sbSlotToBindingMap[slot];
|
||||
|
||||
if (binding < 0)
|
||||
{
|
||||
binding = _gpuAccessor.QueryBindingStorageBuffer(slot);
|
||||
_sbSlotToBindingMap[slot] = binding;
|
||||
string slotNumber = slot.ToString(CultureInfo.InvariantCulture);
|
||||
AddNewStorageBuffer(binding, $"{_stagePrefix}_s{slotNumber}");
|
||||
}
|
||||
|
||||
if (write)
|
||||
{
|
||||
_sbSlotWritten |= 1u << slot;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool TryGetSbSlot(byte sbCbSlot, ushort sbCbOffset, out int slot)
|
||||
{
|
||||
int key = PackSbCbInfo(sbCbSlot, sbCbOffset);
|
||||
|
||||
if (!_sbSlots.TryGetValue(key, out slot))
|
||||
{
|
||||
slot = _sbSlots.Count;
|
||||
|
||||
if (slot >= _sbSlotToBindingMap.Length)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
_sbSlots.Add(key, slot);
|
||||
_sbSlotsReverse.Add(slot, key);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool TryGetConstantBufferSlot(int binding, out int slot)
|
||||
{
|
||||
for (slot = 0; slot < _cbSlotToBindingMap.Length; slot++)
|
||||
|
@ -90,6 +146,34 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
return descriptors;
|
||||
}
|
||||
|
||||
public BufferDescriptor[] GetStorageBufferDescriptors()
|
||||
{
|
||||
var descriptors = new BufferDescriptor[_sbSlots.Count];
|
||||
|
||||
int descriptorIndex = 0;
|
||||
|
||||
foreach ((int key, int slot) in _sbSlots)
|
||||
{
|
||||
int binding = _sbSlotToBindingMap[slot];
|
||||
|
||||
if (binding >= 0)
|
||||
{
|
||||
(int sbCbSlot, int sbCbOffset) = UnpackSbCbInfo(key);
|
||||
descriptors[descriptorIndex++] = new BufferDescriptor(binding, slot, sbCbSlot, sbCbOffset)
|
||||
{
|
||||
Flags = (_sbSlotWritten & (1u << slot)) != 0 ? BufferUsageFlags.Write : BufferUsageFlags.None
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if (descriptors.Length != descriptorIndex)
|
||||
{
|
||||
Array.Resize(ref descriptors, descriptorIndex);
|
||||
}
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
private void AddNewConstantBuffer(int binding, string name)
|
||||
{
|
||||
StructureType type = new StructureType(new[]
|
||||
|
@ -100,6 +184,16 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
_properties.AddConstantBuffer(binding, new BufferDefinition(BufferLayout.Std140, 0, binding, name, type));
|
||||
}
|
||||
|
||||
private void AddNewStorageBuffer(int binding, string name)
|
||||
{
|
||||
StructureType type = new StructureType(new[]
|
||||
{
|
||||
new StructureField(AggregateType.Array | AggregateType.U32, "data", 0)
|
||||
});
|
||||
|
||||
_properties.AddStorageBuffer(binding, new BufferDefinition(BufferLayout.Std430, 1, binding, name, type));
|
||||
}
|
||||
|
||||
public static string GetShaderStagePrefix(ShaderStage stage)
|
||||
{
|
||||
uint index = (uint)stage;
|
||||
|
@ -111,5 +205,15 @@ namespace Ryujinx.Graphics.Shader.Translation
|
|||
|
||||
return _stagePrefixes[index];
|
||||
}
|
||||
|
||||
private static int PackSbCbInfo(int sbCbSlot, int sbCbOffset)
|
||||
{
|
||||
return sbCbOffset | ((int)sbCbSlot << 16);
|
||||
}
|
||||
|
||||
private static (int, int) UnpackSbCbInfo(int key)
|
||||
{
|
||||
return ((byte)(key >> 16), (ushort)key);
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue