aboutsummaryrefslogtreecommitdiff
path: root/src/Ryujinx.Graphics.Gpu/Memory
diff options
context:
space:
mode:
authorgdkchan <gab.dark.100@gmail.com>2023-08-29 21:10:34 -0300
committerGitHub <noreply@github.com>2023-08-29 21:10:34 -0300
commitf09bba82b9366e5912b639a610ae89cbb1cf352c (patch)
tree4811ffa52206eed7cf8aa200c64deb7410e5c56b /src/Ryujinx.Graphics.Gpu/Memory
parent93d78f9ac4a37a50f0cc2e57addd330d072af742 (diff)
Geometry shader emulation for macOS (#5551)
* Implement vertex and geometry shader conversion to compute * Call InitializeReservedCounts for compute too * PR feedback * Set clip distance mask for geometry and tessellation shaders too * Transform feedback emulation only for vertex
Diffstat (limited to 'src/Ryujinx.Graphics.Gpu/Memory')
-rw-r--r--src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs49
-rw-r--r--src/Ryujinx.Graphics.Gpu/Memory/BufferUpdater.cs123
-rw-r--r--src/Ryujinx.Graphics.Gpu/Memory/SupportBufferUpdater.cs85
3 files changed, 155 insertions, 102 deletions
diff --git a/src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs b/src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
index bf4cb5d0..8e9b4b85 100644
--- a/src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
+++ b/src/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
@@ -6,7 +6,6 @@ using Ryujinx.Graphics.Shader;
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
namespace Ryujinx.Graphics.Gpu.Memory
{
@@ -15,9 +14,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// </summary>
class BufferManager
{
- private const int TfInfoVertexCountOffset = Constants.TotalTransformFeedbackBuffers * sizeof(int);
- private const int TfInfoBufferSize = TfInfoVertexCountOffset + sizeof(int);
-
private readonly GpuContext _context;
private readonly GpuChannel _channel;
@@ -104,9 +100,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
private readonly BuffersPerStage[] _gpStorageBuffers;
private readonly BuffersPerStage[] _gpUniformBuffers;
- private BufferHandle _tfInfoBuffer;
- private readonly int[] _tfInfoData;
-
private bool _gpStorageBuffersDirty;
private bool _gpUniformBuffersDirty;
@@ -146,11 +139,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
_bufferTextures = new List<BufferTextureBinding>();
_ranges = new BufferAssignment[Constants.TotalGpUniformBuffers * Constants.ShaderStages];
-
- if (!context.Capabilities.SupportsTransformFeedback)
- {
- _tfInfoData = new int[Constants.TotalTransformFeedbackBuffers];
- }
}
@@ -339,13 +327,10 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <param name="vertexCount">Vertex count per instance</param>
public void SetInstancedDrawVertexCount(int vertexCount)
{
- if (!_context.Capabilities.SupportsTransformFeedback &&
- HasTransformFeedbackOutputs &&
- _tfInfoBuffer != BufferHandle.Null)
+ if (!_context.Capabilities.SupportsTransformFeedback && HasTransformFeedbackOutputs)
{
- Span<byte> data = stackalloc byte[sizeof(int)];
- MemoryMarshal.Cast<byte, int>(data)[0] = vertexCount;
- _context.Renderer.SetBufferData(_tfInfoBuffer, TfInfoVertexCountOffset, data);
+ _context.SupportBufferUpdater.SetTfeVertexCount(vertexCount);
+ _context.SupportBufferUpdater.Commit();
}
}
@@ -607,17 +592,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
else if (HasTransformFeedbackOutputs)
{
- Span<int> info = _tfInfoData.AsSpan();
- Span<BufferAssignment> buffers = stackalloc BufferAssignment[Constants.TotalTransformFeedbackBuffers + 1];
-
- bool needsDataUpdate = false;
-
- if (_tfInfoBuffer == BufferHandle.Null)
- {
- _tfInfoBuffer = _context.Renderer.CreateBuffer(TfInfoBufferSize, BufferAccess.Stream);
- }
-
- buffers[0] = new BufferAssignment(0, new BufferRange(_tfInfoBuffer, 0, TfInfoBufferSize));
+ Span<BufferAssignment> buffers = stackalloc BufferAssignment[Constants.TotalTransformFeedbackBuffers];
int alignment = _context.Capabilities.StorageBufferOffsetAlignment;
@@ -627,7 +602,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
if (tfb.Address == 0)
{
- buffers[1 + index] = new BufferAssignment(1 + index, BufferRange.Empty);
+ buffers[index] = new BufferAssignment(index, BufferRange.Empty);
}
else
{
@@ -637,22 +612,12 @@ namespace Ryujinx.Graphics.Gpu.Memory
int tfeOffset = ((int)tfb.Address & (alignment - 1)) / 4;
- if (info[index] != tfeOffset)
- {
- info[index] = tfeOffset;
- needsDataUpdate = true;
- }
+ _context.SupportBufferUpdater.SetTfeOffset(index, tfeOffset);
- buffers[1 + index] = new BufferAssignment(1 + index, bufferCache.GetBufferRange(address, size, write: true));
+ buffers[index] = new BufferAssignment(index, bufferCache.GetBufferRange(address, size, write: true));
}
}
- if (needsDataUpdate)
- {
- Span<byte> infoData = MemoryMarshal.Cast<int, byte>(info);
- _context.Renderer.SetBufferData(_tfInfoBuffer, 0, infoData);
- }
-
_context.Renderer.Pipeline.SetStorageBuffers(buffers);
}
}
diff --git a/src/Ryujinx.Graphics.Gpu/Memory/BufferUpdater.cs b/src/Ryujinx.Graphics.Gpu/Memory/BufferUpdater.cs
new file mode 100644
index 00000000..02090c04
--- /dev/null
+++ b/src/Ryujinx.Graphics.Gpu/Memory/BufferUpdater.cs
@@ -0,0 +1,123 @@
+using Ryujinx.Graphics.GAL;
+using Ryujinx.Graphics.Shader;
+using System;
+
+namespace Ryujinx.Graphics.Gpu.Memory
+{
+ /// <summary>
+ /// Buffer data updater.
+ /// </summary>
+ class BufferUpdater : IDisposable
+ {
+ private BufferHandle _handle;
+
+ /// <summary>
+ /// Handle of the buffer.
+ /// </summary>
+ public BufferHandle Handle => _handle;
+
+ private readonly IRenderer _renderer;
+ private int _startOffset = -1;
+ private int _endOffset = -1;
+
+ /// <summary>
+ /// Creates a new instance of the buffer updater.
+ /// </summary>
+ /// <param name="renderer">Renderer that the buffer will be used with</param>
+ public BufferUpdater(IRenderer renderer)
+ {
+ _renderer = renderer;
+ }
+
+ /// <summary>
+ /// Mark a region of the buffer as modified and needing to be sent to the GPU.
+ /// </summary>
+ /// <param name="startOffset">Start offset of the region in bytes</param>
+ /// <param name="byteSize">Size of the region in bytes</param>
+ protected void MarkDirty(int startOffset, int byteSize)
+ {
+ int endOffset = startOffset + byteSize;
+
+ if (_startOffset == -1)
+ {
+ _startOffset = startOffset;
+ _endOffset = endOffset;
+ }
+ else
+ {
+ if (startOffset < _startOffset)
+ {
+ _startOffset = startOffset;
+ }
+
+ if (endOffset > _endOffset)
+ {
+ _endOffset = endOffset;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Submits all pending buffer updates to the GPU.
+ /// </summary>
+ /// <param name="data">All data that should be sent to the GPU. Only the modified regions will be updated</param>
+ /// <param name="binding">Optional binding to bind the buffer if a new buffer was created</param>
+ protected void Commit(ReadOnlySpan<byte> data, int binding = -1)
+ {
+ if (_startOffset != -1)
+ {
+ if (_handle == BufferHandle.Null)
+ {
+ _handle = _renderer.CreateBuffer(data.Length, BufferAccess.Stream);
+ _renderer.Pipeline.ClearBuffer(_handle, 0, data.Length, 0);
+
+ if (binding >= 0)
+ {
+ var range = new BufferRange(_handle, 0, data.Length);
+ _renderer.Pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, range) });
+ }
+ };
+
+ _renderer.SetBufferData(_handle, _startOffset, data[_startOffset.._endOffset]);
+
+ _startOffset = -1;
+ _endOffset = -1;
+ }
+ }
+
+ /// <summary>
+ /// Gets a reference to a given element of a vector.
+ /// </summary>
+ /// <param name="vector">Vector to get the element reference from</param>
+ /// <param name="elementIndex">Element index</param>
+ /// <returns>Reference to the specified element</returns>
+ protected static ref T GetElementRef<T>(ref Vector4<T> vector, int elementIndex)
+ {
+ switch (elementIndex)
+ {
+ case 0:
+ return ref vector.X;
+ case 1:
+ return ref vector.Y;
+ case 2:
+ return ref vector.Z;
+ case 3:
+ return ref vector.W;
+ default:
+ throw new ArgumentOutOfRangeException(nameof(elementIndex));
+ }
+ }
+
+ /// <summary>
+ /// Destroys the buffer.
+ /// </summary>
+ public void Dispose()
+ {
+ if (_handle != BufferHandle.Null)
+ {
+ _renderer.DeleteBuffer(_handle);
+ _handle = BufferHandle.Null;
+ }
+ }
+ }
+}
diff --git a/src/Ryujinx.Graphics.Gpu/Memory/SupportBufferUpdater.cs b/src/Ryujinx.Graphics.Gpu/Memory/SupportBufferUpdater.cs
index c1e91c54..fb141db4 100644
--- a/src/Ryujinx.Graphics.Gpu/Memory/SupportBufferUpdater.cs
+++ b/src/Ryujinx.Graphics.Gpu/Memory/SupportBufferUpdater.cs
@@ -9,57 +9,22 @@ namespace Ryujinx.Graphics.Gpu.Memory
/// <summary>
/// Support buffer data updater.
/// </summary>
- class SupportBufferUpdater : IDisposable
+ class SupportBufferUpdater : BufferUpdater
{
private SupportBuffer _data;
- private BufferHandle _handle;
-
- private readonly IRenderer _renderer;
- private int _startOffset = -1;
- private int _endOffset = -1;
/// <summary>
/// Creates a new instance of the support buffer updater.
/// </summary>
/// <param name="renderer">Renderer that the support buffer will be used with</param>
- public SupportBufferUpdater(IRenderer renderer)
+ public SupportBufferUpdater(IRenderer renderer) : base(renderer)
{
- _renderer = renderer;
-
var defaultScale = new Vector4<float> { X = 1f, Y = 0f, Z = 0f, W = 0f };
_data.RenderScale.AsSpan().Fill(defaultScale);
DirtyRenderScale(0, SupportBuffer.RenderScaleMaxCount);
}
/// <summary>
- /// Mark a region of the support buffer as modified and needing to be sent to the GPU.
- /// </summary>
- /// <param name="startOffset">Start offset of the region in bytes</param>
- /// <param name="byteSize">Size of the region in bytes</param>
- private void MarkDirty(int startOffset, int byteSize)
- {
- int endOffset = startOffset + byteSize;
-
- if (_startOffset == -1)
- {
- _startOffset = startOffset;
- _endOffset = endOffset;
- }
- else
- {
- if (startOffset < _startOffset)
- {
- _startOffset = startOffset;
- }
-
- if (endOffset > _endOffset)
- {
- _endOffset = endOffset;
- }
- }
- }
-
- /// <summary>
/// Marks the fragment render scale count as being modified.
/// </summary>
private void DirtyFragmentRenderScaleCount()
@@ -220,40 +185,40 @@ namespace Ryujinx.Graphics.Gpu.Memory
}
/// <summary>
- /// Submits all pending buffer updates to the GPU.
+ /// Sets offset for the misaligned portion of a transform feedback buffer, and the buffer size, for transform feedback emulation.
/// </summary>
- public void Commit()
+ /// <param name="bufferIndex">Index of the transform feedback buffer</param>
+ /// <param name="offset">Misaligned offset of the buffer</param>
+ public void SetTfeOffset(int bufferIndex, int offset)
{
- if (_startOffset != -1)
- {
- if (_handle == BufferHandle.Null)
- {
- _handle = _renderer.CreateBuffer(SupportBuffer.RequiredSize, BufferAccess.Stream);
- _renderer.Pipeline.ClearBuffer(_handle, 0, SupportBuffer.RequiredSize, 0);
+ ref int currentOffset = ref GetElementRef(ref _data.TfeOffset, bufferIndex);
- var range = new BufferRange(_handle, 0, SupportBuffer.RequiredSize);
- _renderer.Pipeline.SetUniformBuffers(stackalloc[] { new BufferAssignment(0, range) });
- }
-
- ReadOnlySpan<byte> data = MemoryMarshal.Cast<SupportBuffer, byte>(MemoryMarshal.CreateSpan(ref _data, 1));
-
- _renderer.SetBufferData(_handle, _startOffset, data[_startOffset.._endOffset]);
-
- _startOffset = -1;
- _endOffset = -1;
+ if (currentOffset != offset)
+ {
+ currentOffset = offset;
+ MarkDirty(SupportBuffer.TfeOffsetOffset + bufferIndex * sizeof(int), sizeof(int));
}
}
/// <summary>
- /// Destroys the support buffer.
+ /// Sets the vertex count used for transform feedback emulation with instanced draws.
/// </summary>
- public void Dispose()
+ /// <param name="vertexCount">Vertex count of the instanced draw</param>
+ public void SetTfeVertexCount(int vertexCount)
{
- if (_handle != BufferHandle.Null)
+ if (_data.TfeVertexCount.X != vertexCount)
{
- _renderer.DeleteBuffer(_handle);
- _handle = BufferHandle.Null;
+ _data.TfeVertexCount.X = vertexCount;
+ MarkDirty(SupportBuffer.TfeVertexCountOffset, sizeof(int));
}
}
+
+ /// <summary>
+ /// Submits all pending buffer updates to the GPU.
+ /// </summary>
+ public void Commit()
+ {
+ Commit(MemoryMarshal.Cast<SupportBuffer, byte>(MemoryMarshal.CreateSpan(ref _data, 1)), SupportBuffer.Binding);
+ }
}
}