From f09bba82b9366e5912b639a610ae89cbb1cf352c Mon Sep 17 00:00:00 2001 From: gdkchan Date: Tue, 29 Aug 2023 21:10:34 -0300 Subject: 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 --- .../Threed/ComputeDraw/VertexInfoBufferUpdater.cs | 141 +++++++++++++++++++++ 1 file changed, 141 insertions(+) create mode 100644 src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VertexInfoBufferUpdater.cs (limited to 'src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VertexInfoBufferUpdater.cs') diff --git a/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VertexInfoBufferUpdater.cs b/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VertexInfoBufferUpdater.cs new file mode 100644 index 00000000..65f556fc --- /dev/null +++ b/src/Ryujinx.Graphics.Gpu/Engine/Threed/ComputeDraw/VertexInfoBufferUpdater.cs @@ -0,0 +1,141 @@ +using Ryujinx.Graphics.GAL; +using Ryujinx.Graphics.Gpu.Memory; +using Ryujinx.Graphics.Shader; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Ryujinx.Graphics.Gpu.Engine.Threed.ComputeDraw +{ + /// + /// Vertex info buffer data updater. + /// + class VertexInfoBufferUpdater : BufferUpdater + { + private VertexInfoBuffer _data; + + /// + /// Creates a new instance of the vertex info buffer updater. + /// + /// Renderer that the vertex info buffer will be used with + public VertexInfoBufferUpdater(IRenderer renderer) : base(renderer) + { + } + + /// + /// Sets vertex data related counts. + /// + /// Number of vertices used on the draw + /// Number of draw instances + /// Index of the first vertex on the vertex buffer + /// Index of the first instanced vertex on the vertex buffer + public void SetVertexCounts(int vertexCount, int instanceCount, int firstVertex, int firstInstance) + { + if (_data.VertexCounts.X != vertexCount) + { + _data.VertexCounts.X = vertexCount; + MarkDirty(VertexInfoBuffer.VertexCountsOffset, sizeof(int)); + } + + if (_data.VertexCounts.Y != instanceCount) + { + _data.VertexCounts.Y = instanceCount; + MarkDirty(VertexInfoBuffer.VertexCountsOffset + sizeof(int), sizeof(int)); + } + + if (_data.VertexCounts.Z != firstVertex) + { + _data.VertexCounts.Z = firstVertex; + MarkDirty(VertexInfoBuffer.VertexCountsOffset + sizeof(int) * 2, sizeof(int)); + } + + if (_data.VertexCounts.W != firstInstance) + { + _data.VertexCounts.W = firstInstance; + MarkDirty(VertexInfoBuffer.VertexCountsOffset + sizeof(int) * 3, sizeof(int)); + } + } + + /// + /// Sets vertex data related counts. + /// + /// Number of primitives consumed by the geometry shader + public void SetGeometryCounts(int primitivesCount) + { + if (_data.GeometryCounts.X != primitivesCount) + { + _data.GeometryCounts.X = primitivesCount; + MarkDirty(VertexInfoBuffer.GeometryCountsOffset, sizeof(int)); + } + } + + /// + /// Sets a vertex stride and related data. + /// + /// Index of the vertex stride to be updated + /// Stride divided by the component or format size + /// Number of components that the format has + public void SetVertexStride(int index, int stride, int componentCount) + { + if (_data.VertexStrides[index].X != stride) + { + _data.VertexStrides[index].X = stride; + MarkDirty(VertexInfoBuffer.VertexStridesOffset + index * Unsafe.SizeOf>(), sizeof(int)); + } + + for (int c = 1; c < 4; c++) + { + int value = c < componentCount ? 1 : 0; + + ref int currentValue = ref GetElementRef(ref _data.VertexStrides[index], c); + + if (currentValue != value) + { + currentValue = value; + MarkDirty(VertexInfoBuffer.VertexStridesOffset + index * Unsafe.SizeOf>() + c * sizeof(int), sizeof(int)); + } + } + } + + /// + /// Sets a vertex offset and related data. + /// + /// Index of the vertex offset to be updated + /// Offset divided by the component or format size + /// If the draw is instanced, should have the vertex divisor value, otherwise should be zero + public void SetVertexOffset(int index, int offset, int divisor) + { + if (_data.VertexOffsets[index].X != offset) + { + _data.VertexOffsets[index].X = offset; + MarkDirty(VertexInfoBuffer.VertexOffsetsOffset + index * Unsafe.SizeOf>(), sizeof(int)); + } + + if (_data.VertexOffsets[index].Y != divisor) + { + _data.VertexOffsets[index].Y = divisor; + MarkDirty(VertexInfoBuffer.VertexOffsetsOffset + index * Unsafe.SizeOf>() + sizeof(int), sizeof(int)); + } + } + + /// + /// Sets the offset of the index buffer. + /// + /// Offset divided by the component size + public void SetIndexBufferOffset(int offset) + { + if (_data.GeometryCounts.W != offset) + { + _data.GeometryCounts.W = offset; + MarkDirty(VertexInfoBuffer.GeometryCountsOffset + sizeof(int) * 3, sizeof(int)); + } + } + + /// + /// Submits all pending buffer updates to the GPU. + /// + public void Commit() + { + Commit(MemoryMarshal.Cast(MemoryMarshal.CreateSpan(ref _data, 1))); + } + } +} -- cgit v1.2.3