diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2023-08-29 21:10:34 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-08-29 21:10:34 -0300 |
| commit | f09bba82b9366e5912b639a610ae89cbb1cf352c (patch) | |
| tree | 4811ffa52206eed7cf8aa200c64deb7410e5c56b /src/Ryujinx.Graphics.Gpu/Memory | |
| parent | 93d78f9ac4a37a50f0cc2e57addd330d072af742 (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.cs | 49 | ||||
| -rw-r--r-- | src/Ryujinx.Graphics.Gpu/Memory/BufferUpdater.cs | 123 | ||||
| -rw-r--r-- | src/Ryujinx.Graphics.Gpu/Memory/SupportBufferUpdater.cs | 85 |
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); + } } } |
