using Ryujinx.Common; using Ryujinx.Graphics.GAL; using System; using System.Runtime.InteropServices; namespace Ryujinx.Graphics.Gpu.Engine { /// /// Holds inline index buffer state. /// The inline index buffer data is sent to the GPU through the command buffer. /// struct IbStreamer { private BufferHandle _inlineIndexBuffer; private int _inlineIndexBufferSize; private int _inlineIndexCount; public bool HasInlineIndexData => _inlineIndexCount != 0; /// /// Gets the handle for the host buffer currently holding the inline index buffer data. /// /// Host buffer handle public BufferHandle GetInlineIndexBuffer() { return _inlineIndexBuffer; } /// /// Gets the number of elements on the current inline index buffer, /// while also reseting it to zero for the next draw. /// /// Inline index bufffer count public int GetAndResetInlineIndexCount() { int temp = _inlineIndexCount; _inlineIndexCount = 0; return temp; } /// /// Pushes four 8-bit index buffer elements. /// /// Host renderer /// Method call argument public void VbElementU8(IRenderer renderer, int argument) { byte i0 = (byte)argument; byte i1 = (byte)(argument >> 8); byte i2 = (byte)(argument >> 16); byte i3 = (byte)(argument >> 24); Span data = stackalloc uint[4]; data[0] = i0; data[1] = i1; data[2] = i2; data[3] = i3; int offset = _inlineIndexCount * 4; renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast(data)); _inlineIndexCount += 4; } /// /// Pushes two 16-bit index buffer elements. /// /// Host renderer /// Method call argument public void VbElementU16(IRenderer renderer, int argument) { ushort i0 = (ushort)argument; ushort i1 = (ushort)(argument >> 16); Span data = stackalloc uint[2]; data[0] = i0; data[1] = i1; int offset = _inlineIndexCount * 4; renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast(data)); _inlineIndexCount += 2; } /// /// Pushes one 32-bit index buffer element. /// /// Host renderer /// Method call argument public void VbElementU32(IRenderer renderer, int argument) { uint i0 = (uint)argument; Span data = stackalloc uint[1]; data[0] = i0; int offset = _inlineIndexCount++ * 4; renderer.SetBufferData(GetInlineIndexBuffer(renderer, offset), offset, MemoryMarshal.Cast(data)); } /// /// Gets the handle of a buffer large enough to hold the data that will be written to . /// /// Host renderer /// Offset where the data will be written /// Buffer handle private BufferHandle GetInlineIndexBuffer(IRenderer renderer, int offset) { // Calculate a reasonable size for the buffer that can fit all the data, // and that also won't require frequent resizes if we need to push more data. int size = BitUtils.AlignUp(offset + 0x10, 0x200); if (_inlineIndexBuffer == BufferHandle.Null) { _inlineIndexBuffer = renderer.CreateBuffer(size); _inlineIndexBufferSize = size; } else if (_inlineIndexBufferSize < size) { BufferHandle oldBuffer = _inlineIndexBuffer; int oldSize = _inlineIndexBufferSize; _inlineIndexBuffer = renderer.CreateBuffer(size); _inlineIndexBufferSize = size; renderer.Pipeline.CopyBuffer(oldBuffer, _inlineIndexBuffer, 0, 0, oldSize); renderer.DeleteBuffer(oldBuffer); } return _inlineIndexBuffer; } } }