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))); } } }