aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Audio/Renderer/Common
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Audio/Renderer/Common')
-rw-r--r--Ryujinx.Audio/Renderer/Common/AuxiliaryBufferAddresses.cs30
-rw-r--r--Ryujinx.Audio/Renderer/Common/BehaviourParameter.cs67
-rw-r--r--Ryujinx.Audio/Renderer/Common/EdgeMatrix.cs167
-rw-r--r--Ryujinx.Audio/Renderer/Common/EffectType.cs60
-rw-r--r--Ryujinx.Audio/Renderer/Common/MemoryPoolUserState.cs60
-rw-r--r--Ryujinx.Audio/Renderer/Common/NodeIdHelper.cs45
-rw-r--r--Ryujinx.Audio/Renderer/Common/NodeIdType.cs50
-rw-r--r--Ryujinx.Audio/Renderer/Common/NodeStates.cs246
-rw-r--r--Ryujinx.Audio/Renderer/Common/PerformanceDetailType.cs34
-rw-r--r--Ryujinx.Audio/Renderer/Common/PerformanceEntryType.cs28
-rw-r--r--Ryujinx.Audio/Renderer/Common/PlayState.cs40
-rw-r--r--Ryujinx.Audio/Renderer/Common/ReverbEarlyMode.cs50
-rw-r--r--Ryujinx.Audio/Renderer/Common/ReverbLateMode.cs55
-rw-r--r--Ryujinx.Audio/Renderer/Common/SinkType.cs40
-rw-r--r--Ryujinx.Audio/Renderer/Common/UpdateDataHeader.cs50
-rw-r--r--Ryujinx.Audio/Renderer/Common/VoiceUpdateState.cs121
-rw-r--r--Ryujinx.Audio/Renderer/Common/WaveBuffer.cs99
-rw-r--r--Ryujinx.Audio/Renderer/Common/WorkBufferAllocator.cs78
18 files changed, 1320 insertions, 0 deletions
diff --git a/Ryujinx.Audio/Renderer/Common/AuxiliaryBufferAddresses.cs b/Ryujinx.Audio/Renderer/Common/AuxiliaryBufferAddresses.cs
new file mode 100644
index 00000000..5d826569
--- /dev/null
+++ b/Ryujinx.Audio/Renderer/Common/AuxiliaryBufferAddresses.cs
@@ -0,0 +1,30 @@
+//
+// Copyright (c) 2019-2021 Ryujinx
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+//
+
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct AuxiliaryBufferAddresses
+ {
+ public ulong SendBufferInfo;
+ public ulong SendBufferInfoBase;
+ public ulong ReturnBufferInfo;
+ public ulong ReturnBufferInfoBase;
+ }
+}
diff --git a/Ryujinx.Audio/Renderer/Common/BehaviourParameter.cs b/Ryujinx.Audio/Renderer/Common/BehaviourParameter.cs
new file mode 100644
index 00000000..0de3d571
--- /dev/null
+++ b/Ryujinx.Audio/Renderer/Common/BehaviourParameter.cs
@@ -0,0 +1,67 @@
+//
+// Copyright (c) 2019-2021 Ryujinx
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+//
+
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ /// <summary>
+ /// Represents the input parameter for <see cref="Server.BehaviourContext"/>.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct BehaviourParameter
+ {
+ /// <summary>
+ /// The current audio renderer revision in use.
+ /// </summary>
+ public int UserRevision;
+
+ /// <summary>
+ /// Reserved/padding.
+ /// </summary>
+ private uint _padding;
+
+ /// <summary>
+ /// The flags given controlling behaviour of the audio renderer
+ /// </summary>
+ /// <remarks>See <see cref="Server.BehaviourContext.UpdateFlags(ulong)"/> and <see cref="Server.BehaviourContext.IsMemoryPoolForceMappingEnabled"/>.</remarks>
+ public ulong Flags;
+
+ /// <summary>
+ /// Represents an error during <see cref="Server.AudioRenderSystem.Update(System.Memory{byte}, System.Memory{byte}, System.ReadOnlyMemory{byte})"/>.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct ErrorInfo
+ {
+ /// <summary>
+ /// The error code to report.
+ /// </summary>
+ public ResultCode ErrorCode;
+
+ /// <summary>
+ /// Reserved/padding.
+ /// </summary>
+ private uint _padding;
+
+ /// <summary>
+ /// Extra information given with the <see cref="ResultCode"/>
+ /// </summary>
+ /// <remarks>This is usually used to report a faulting cpu address when a <see cref="Server.MemoryPool.MemoryPoolState"/> mapping fail.</remarks>
+ public ulong ExtraErrorInfo;
+ }
+ }
+}
diff --git a/Ryujinx.Audio/Renderer/Common/EdgeMatrix.cs b/Ryujinx.Audio/Renderer/Common/EdgeMatrix.cs
new file mode 100644
index 00000000..7423eda4
--- /dev/null
+++ b/Ryujinx.Audio/Renderer/Common/EdgeMatrix.cs
@@ -0,0 +1,167 @@
+//
+// Copyright (c) 2019-2021 Ryujinx
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+//
+
+using Ryujinx.Audio.Renderer.Utils;
+using Ryujinx.Common;
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ /// <summary>
+ /// Represents a adjacent matrix.
+ /// </summary>
+ /// <remarks>This is used for splitter routing.</remarks>
+ public class EdgeMatrix
+ {
+ /// <summary>
+ /// Backing <see cref="BitArray"/> used for node connections.
+ /// </summary>
+ private BitArray _storage;
+
+ /// <summary>
+ /// The count of nodes of the current instance.
+ /// </summary>
+ private int _nodeCount;
+
+ /// <summary>
+ /// Get the required work buffer size memory needed for the <see cref="EdgeMatrix"/>.
+ /// </summary>
+ /// <param name="nodeCount">The count of nodes.</param>
+ /// <returns>The size required for the given <paramref name="nodeCount"/>.</returns>
+ public static int GetWorkBufferSize(int nodeCount)
+ {
+ int size = BitUtils.AlignUp(nodeCount * nodeCount, Constants.BufferAlignment);
+
+ return size / Unsafe.SizeOf<byte>();
+ }
+
+ /// <summary>
+ /// Initializes the <see cref="EdgeMatrix"/> instance with backing memory.
+ /// </summary>
+ /// <param name="edgeMatrixWorkBuffer">The backing memory.</param>
+ /// <param name="nodeCount">The count of nodes.</param>
+ public void Initialize(Memory<byte> edgeMatrixWorkBuffer, int nodeCount)
+ {
+ Debug.Assert(edgeMatrixWorkBuffer.Length >= GetWorkBufferSize(nodeCount));
+
+ _storage = new BitArray(edgeMatrixWorkBuffer);
+
+ _nodeCount = nodeCount;
+
+ _storage.Reset();
+ }
+
+ /// <summary>
+ /// Test if the bit at the given index is set.
+ /// </summary>
+ /// <param name="index">A bit index.</param>
+ /// <returns>Returns true if the bit at the given index is set</returns>
+ public bool Test(int index)
+ {
+ return _storage.Test(index);
+ }
+
+ /// <summary>
+ /// Reset all bits in the storage.
+ /// </summary>
+ public void Reset()
+ {
+ _storage.Reset();
+ }
+
+ /// <summary>
+ /// Reset the bit at the given index.
+ /// </summary>
+ /// <param name="index">A bit index.</param>
+ public void Reset(int index)
+ {
+ _storage.Reset(index);
+ }
+
+ /// <summary>
+ /// Set the bit at the given index.
+ /// </summary>
+ /// <param name="index">A bit index.</param>
+ public void Set(int index)
+ {
+ _storage.Set(index);
+ }
+
+ /// <summary>
+ /// Connect a given source to a given destination.
+ /// </summary>
+ /// <param name="source">The source index.</param>
+ /// <param name="destination">The destination index.</param>
+ public void Connect(int source, int destination)
+ {
+ Debug.Assert(source < _nodeCount);
+ Debug.Assert(destination < _nodeCount);
+
+ _storage.Set(_nodeCount * source + destination);
+ }
+
+ /// <summary>
+ /// Check if the given source is connected to the given destination.
+ /// </summary>
+ /// <param name="source">The source index.</param>
+ /// <param name="destination">The destination index.</param>
+ /// <returns>Returns true if the given source is connected to the given destination.</returns>
+ public bool Connected(int source, int destination)
+ {
+ Debug.Assert(source < _nodeCount);
+ Debug.Assert(destination < _nodeCount);
+
+ return _storage.Test(_nodeCount * source + destination);
+ }
+
+ /// <summary>
+ /// Disconnect a given source from a given destination.
+ /// </summary>
+ /// <param name="source">The source index.</param>
+ /// <param name="destination">The destination index.</param>
+ public void Disconnect(int source, int destination)
+ {
+ Debug.Assert(source < _nodeCount);
+ Debug.Assert(destination < _nodeCount);
+
+ _storage.Reset(_nodeCount * source + destination);
+ }
+
+ /// <summary>
+ /// Remove all edges from a given source.
+ /// </summary>
+ /// <param name="source">The source index.</param>
+ public void RemoveEdges(int source)
+ {
+ for (int i = 0; i < _nodeCount; i++)
+ {
+ Disconnect(source, i);
+ }
+ }
+
+ /// <summary>
+ /// Get the total node count.
+ /// </summary>
+ /// <returns>The total node count.</returns>
+ public int GetNodeCount()
+ {
+ return _nodeCount;
+ }
+ }
+}
diff --git a/Ryujinx.Audio/Renderer/Common/EffectType.cs b/Ryujinx.Audio/Renderer/Common/EffectType.cs
new file mode 100644
index 00000000..082f94f8
--- /dev/null
+++ b/Ryujinx.Audio/Renderer/Common/EffectType.cs
@@ -0,0 +1,60 @@
+//
+// Copyright (c) 2019-2021 Ryujinx
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+//
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ /// <summary>
+ /// The type of an effect.
+ /// </summary>
+ public enum EffectType : byte
+ {
+ /// <summary>
+ /// Invalid effect.
+ /// </summary>
+ Invalid,
+
+ /// <summary>
+ /// Effect applying additional mixing capability.
+ /// </summary>
+ BufferMix,
+
+ /// <summary>
+ /// Effect applying custom user effect (via auxiliary buffers).
+ /// </summary>
+ AuxiliaryBuffer,
+
+ /// <summary>
+ /// Effect applying a delay.
+ /// </summary>
+ Delay,
+
+ /// <summary>
+ /// Effect applying a reverberation effect via a given preset.
+ /// </summary>
+ Reverb,
+
+ /// <summary>
+ /// Effect applying a 3D reverberation effect via a given preset.
+ /// </summary>
+ Reverb3d,
+
+ /// <summary>
+ /// Effect applying a biquad filter.
+ /// </summary>
+ BiquadFilter
+ }
+}
diff --git a/Ryujinx.Audio/Renderer/Common/MemoryPoolUserState.cs b/Ryujinx.Audio/Renderer/Common/MemoryPoolUserState.cs
new file mode 100644
index 00000000..7f9765d9
--- /dev/null
+++ b/Ryujinx.Audio/Renderer/Common/MemoryPoolUserState.cs
@@ -0,0 +1,60 @@
+//
+// Copyright (c) 2019-2021 Ryujinx
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+//
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ /// <summary>
+ /// Represents the state of a memory pool.
+ /// </summary>
+ public enum MemoryPoolUserState : uint
+ {
+ /// <summary>
+ /// Invalid state.
+ /// </summary>
+ Invalid = 0,
+
+ /// <summary>
+ /// The memory pool is new. (client side only)
+ /// </summary>
+ New = 1,
+
+ /// <summary>
+ /// The user asked to detach the memory pool from the <see cref="Dsp.AudioProcessor"/>.
+ /// </summary>
+ RequestDetach = 2,
+
+ /// <summary>
+ /// The memory pool is detached from the <see cref="Dsp.AudioProcessor"/>.
+ /// </summary>
+ Detached = 3,
+
+ /// <summary>
+ /// The user asked to attach the memory pool to the <see cref="Dsp.AudioProcessor"/>.
+ /// </summary>
+ RequestAttach = 4,
+
+ /// <summary>
+ /// The memory pool is attached to the <see cref="Dsp.AudioProcessor"/>.
+ /// </summary>
+ Attached = 5,
+
+ /// <summary>
+ /// The memory pool is released. (client side only)
+ /// </summary>
+ Released = 6
+ }
+}
diff --git a/Ryujinx.Audio/Renderer/Common/NodeIdHelper.cs b/Ryujinx.Audio/Renderer/Common/NodeIdHelper.cs
new file mode 100644
index 00000000..9bf1f2d0
--- /dev/null
+++ b/Ryujinx.Audio/Renderer/Common/NodeIdHelper.cs
@@ -0,0 +1,45 @@
+//
+// Copyright (c) 2019-2021 Ryujinx
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+//
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ /// <summary>
+ /// Helper for manipulating node ids.
+ /// </summary>
+ public static class NodeIdHelper
+ {
+ /// <summary>
+ /// Get the type of a node from a given node id.
+ /// </summary>
+ /// <param name="nodeId">Id of the node.</param>
+ /// <returns>The type of the node.</returns>
+ public static NodeIdType GetType(int nodeId)
+ {
+ return (NodeIdType)(nodeId >> 28);
+ }
+
+ /// <summary>
+ /// Get the base of a node from a given node id.
+ /// </summary>
+ /// <param name="nodeId">Id of the node.</param>
+ /// <returns>The base of the node.</returns>
+ public static int GetBase(int nodeId)
+ {
+ return (nodeId >> 16) & 0xFFF;
+ }
+ }
+}
diff --git a/Ryujinx.Audio/Renderer/Common/NodeIdType.cs b/Ryujinx.Audio/Renderer/Common/NodeIdType.cs
new file mode 100644
index 00000000..4a4796a9
--- /dev/null
+++ b/Ryujinx.Audio/Renderer/Common/NodeIdType.cs
@@ -0,0 +1,50 @@
+//
+// Copyright (c) 2019-2021 Ryujinx
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+//
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ /// <summary>
+ /// The type of a node.
+ /// </summary>
+ public enum NodeIdType : byte
+ {
+ /// <summary>
+ /// Invalid node id.
+ /// </summary>
+ Invalid = 0,
+
+ /// <summary>
+ /// Voice related node id. (data source, biquad filter, ...)
+ /// </summary>
+ Voice = 1,
+
+ /// <summary>
+ /// Mix related node id. (mix, effects, splitters, ...)
+ /// </summary>
+ Mix = 2,
+
+ /// <summary>
+ /// Sink related node id. (device &amp; circular buffer sink)
+ /// </summary>
+ Sink = 3,
+
+ /// <summary>
+ /// Performance monitoring related node id (performance commands)
+ /// </summary>
+ Performance = 15
+ }
+}
diff --git a/Ryujinx.Audio/Renderer/Common/NodeStates.cs b/Ryujinx.Audio/Renderer/Common/NodeStates.cs
new file mode 100644
index 00000000..5efd7767
--- /dev/null
+++ b/Ryujinx.Audio/Renderer/Common/NodeStates.cs
@@ -0,0 +1,246 @@
+//
+// Copyright (c) 2019-2021 Ryujinx
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+//
+
+using Ryujinx.Audio.Renderer.Utils;
+using System;
+using System.Diagnostics;
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ public class NodeStates
+ {
+ private class Stack
+ {
+ private Memory<int> _storage;
+ private int _index;
+
+ private int _nodeCount;
+
+ public void Reset(Memory<int> storage, int nodeCount)
+ {
+ Debug.Assert(storage.Length * sizeof(int) >= CalcBufferSize(nodeCount));
+
+ _storage = storage;
+ _index = 0;
+ _nodeCount = nodeCount;
+ }
+
+ public int GetCurrentCount()
+ {
+ return _index;
+ }
+
+ public void Push(int data)
+ {
+ Debug.Assert(_index + 1 <= _nodeCount);
+
+ _storage.Span[_index++] = data;
+ }
+
+ public int Pop()
+ {
+ Debug.Assert(_index > 0);
+
+ return _storage.Span[--_index];
+ }
+
+ public int Top()
+ {
+ return _storage.Span[_index - 1];
+ }
+
+ public static int CalcBufferSize(int nodeCount)
+ {
+ return nodeCount * sizeof(int);
+ }
+ }
+
+ private int _nodeCount;
+ private EdgeMatrix _discovered;
+ private EdgeMatrix _finished;
+ private Memory<int> _resultArray;
+ private Stack _stack;
+ private int _tsortResultIndex;
+
+ private enum NodeState : byte
+ {
+ Unknown,
+ Discovered,
+ Finished
+ }
+
+ public NodeStates()
+ {
+ _stack = new Stack();
+ _discovered = new EdgeMatrix();
+ _finished = new EdgeMatrix();
+ }
+
+ public static int GetWorkBufferSize(int nodeCount)
+ {
+ return Stack.CalcBufferSize(nodeCount * nodeCount) + 0xC * nodeCount + 2 * EdgeMatrix.GetWorkBufferSize(nodeCount);
+ }
+
+ public void Initialize(Memory<byte> nodeStatesWorkBuffer, int nodeCount)
+ {
+ int workBufferSize = GetWorkBufferSize(nodeCount);
+
+ Debug.Assert(nodeStatesWorkBuffer.Length >= workBufferSize);
+
+ _nodeCount = nodeCount;
+
+ int edgeMatrixWorkBufferSize = EdgeMatrix.GetWorkBufferSize(nodeCount);
+
+ _discovered.Initialize(nodeStatesWorkBuffer.Slice(0, edgeMatrixWorkBufferSize), nodeCount);
+ _finished.Initialize(nodeStatesWorkBuffer.Slice(edgeMatrixWorkBufferSize, edgeMatrixWorkBufferSize), nodeCount);
+
+ nodeStatesWorkBuffer = nodeStatesWorkBuffer.Slice(edgeMatrixWorkBufferSize * 2);
+
+ _resultArray = SpanMemoryManager<int>.Cast(nodeStatesWorkBuffer.Slice(0, sizeof(int) * nodeCount));
+
+ nodeStatesWorkBuffer = nodeStatesWorkBuffer.Slice(sizeof(int) * nodeCount);
+
+ Memory<int> stackWorkBuffer = SpanMemoryManager<int>.Cast(nodeStatesWorkBuffer.Slice(0, Stack.CalcBufferSize(nodeCount * nodeCount)));
+
+ _stack.Reset(stackWorkBuffer, nodeCount * nodeCount);
+ }
+
+ private void Reset()
+ {
+ _discovered.Reset();
+ _finished.Reset();
+ _tsortResultIndex = 0;
+ _resultArray.Span.Fill(-1);
+ }
+
+ private NodeState GetState(int index)
+ {
+ Debug.Assert(index < _nodeCount);
+
+ if (_discovered.Test(index))
+ {
+ Debug.Assert(!_finished.Test(index));
+
+ return NodeState.Discovered;
+ }
+ else if (_finished.Test(index))
+ {
+ Debug.Assert(!_discovered.Test(index));
+
+ return NodeState.Finished;
+ }
+
+ return NodeState.Unknown;
+ }
+
+ private void SetState(int index, NodeState state)
+ {
+ switch (state)
+ {
+ case NodeState.Unknown:
+ _discovered.Reset(index);
+ _finished.Reset(index);
+ break;
+ case NodeState.Discovered:
+ _discovered.Set(index);
+ _finished.Reset(index);
+ break;
+ case NodeState.Finished:
+ _finished.Set(index);
+ _discovered.Reset(index);
+ break;
+ }
+ }
+
+ private void PushTsortResult(int index)
+ {
+ Debug.Assert(index < _nodeCount);
+
+ _resultArray.Span[_tsortResultIndex++] = index;
+ }
+
+ public ReadOnlySpan<int> GetTsortResult()
+ {
+ return _resultArray.Span.Slice(0, _tsortResultIndex);
+ }
+
+ public bool Sort(EdgeMatrix edgeMatrix)
+ {
+ Reset();
+
+ if (_nodeCount <= 0)
+ {
+ return true;
+ }
+
+ for (int i = 0; i < _nodeCount; i++)
+ {
+ if (GetState(i) == NodeState.Unknown)
+ {
+ _stack.Push(i);
+ }
+
+ while (_stack.GetCurrentCount() > 0)
+ {
+ int topIndex = _stack.Top();
+
+ NodeState topState = GetState(topIndex);
+
+ if (topState == NodeState.Discovered)
+ {
+ SetState(topIndex, NodeState.Finished);
+ PushTsortResult(topIndex);
+ _stack.Pop();
+ }
+ else if (topState == NodeState.Finished)
+ {
+ _stack.Pop();
+ }
+ else
+ {
+ if (topState == NodeState.Unknown)
+ {
+ SetState(topIndex, NodeState.Discovered);
+ }
+
+ for (int j = 0; j < edgeMatrix.GetNodeCount(); j++)
+ {
+ if (edgeMatrix.Connected(topIndex, j))
+ {
+ NodeState jState = GetState(j);
+
+ if (jState == NodeState.Unknown)
+ {
+ _stack.Push(j);
+ }
+ // Found a loop, reset and propagate rejection.
+ else if (jState == NodeState.Discovered)
+ {
+ Reset();
+
+ return false;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return true;
+ }
+ }
+}
diff --git a/Ryujinx.Audio/Renderer/Common/PerformanceDetailType.cs b/Ryujinx.Audio/Renderer/Common/PerformanceDetailType.cs
new file mode 100644
index 00000000..a92bd0cc
--- /dev/null
+++ b/Ryujinx.Audio/Renderer/Common/PerformanceDetailType.cs
@@ -0,0 +1,34 @@
+//
+// Copyright (c) 2019-2021 Ryujinx
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+//
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ public enum PerformanceDetailType : byte
+ {
+ Unknown,
+ PcmInt16,
+ Adpcm,
+ VolumeRamp,
+ BiquadFilter,
+ Mix,
+ Delay,
+ Aux,
+ Reverb,
+ Reverb3d,
+ PcmFloat
+ }
+}
diff --git a/Ryujinx.Audio/Renderer/Common/PerformanceEntryType.cs b/Ryujinx.Audio/Renderer/Common/PerformanceEntryType.cs
new file mode 100644
index 00000000..0d9a547d
--- /dev/null
+++ b/Ryujinx.Audio/Renderer/Common/PerformanceEntryType.cs
@@ -0,0 +1,28 @@
+//
+// Copyright (c) 2019-2021 Ryujinx
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+//
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ public enum PerformanceEntryType : byte
+ {
+ Invalid,
+ Voice,
+ SubMix,
+ FinalMix,
+ Sink
+ }
+}
diff --git a/Ryujinx.Audio/Renderer/Common/PlayState.cs b/Ryujinx.Audio/Renderer/Common/PlayState.cs
new file mode 100644
index 00000000..7771c154
--- /dev/null
+++ b/Ryujinx.Audio/Renderer/Common/PlayState.cs
@@ -0,0 +1,40 @@
+//
+// Copyright (c) 2019-2021 Ryujinx
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+//
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ /// <summary>
+ /// Common play state.
+ /// </summary>
+ public enum PlayState : byte
+ {
+ /// <summary>
+ /// The user request the voice to be started.
+ /// </summary>
+ Start,
+
+ /// <summary>
+ /// The user request the voice to be stopped.
+ /// </summary>
+ Stop,
+
+ /// <summary>
+ /// The user request the voice to be paused.
+ /// </summary>
+ Pause
+ }
+}
diff --git a/Ryujinx.Audio/Renderer/Common/ReverbEarlyMode.cs b/Ryujinx.Audio/Renderer/Common/ReverbEarlyMode.cs
new file mode 100644
index 00000000..a0f65e5e
--- /dev/null
+++ b/Ryujinx.Audio/Renderer/Common/ReverbEarlyMode.cs
@@ -0,0 +1,50 @@
+//
+// Copyright (c) 2019-2021 Ryujinx
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+//
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ /// <summary>
+ /// Early reverb reflection.
+ /// </summary>
+ public enum ReverbEarlyMode : uint
+ {
+ /// <summary>
+ /// Room early reflection. (small acoustic space, fast reflection)
+ /// </summary>
+ Room,
+
+ /// <summary>
+ /// Chamber early reflection. (bigger than <see cref="Room"/>'s acoustic space, short reflection)
+ /// </summary>
+ Chamber,
+
+ /// <summary>
+ /// Hall early reflection. (large acoustic space, warm reflection)
+ /// </summary>
+ Hall,
+
+ /// <summary>
+ /// Cathedral early reflection. (very large acoustic space, pronounced bright reflection)
+ /// </summary>
+ Cathedral,
+
+ /// <summary>
+ /// No early reflection.
+ /// </summary>
+ Disabled
+ }
+}
diff --git a/Ryujinx.Audio/Renderer/Common/ReverbLateMode.cs b/Ryujinx.Audio/Renderer/Common/ReverbLateMode.cs
new file mode 100644
index 00000000..57760821
--- /dev/null
+++ b/Ryujinx.Audio/Renderer/Common/ReverbLateMode.cs
@@ -0,0 +1,55 @@
+//
+// Copyright (c) 2019-2021 Ryujinx
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+//
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ /// <summary>
+ /// Late reverb reflection.
+ /// </summary>
+ public enum ReverbLateMode : uint
+ {
+ /// <summary>
+ /// Room late reflection. (small acoustic space, fast reflection)
+ /// </summary>
+ Room,
+
+ /// <summary>
+ /// Hall late reflection. (large acoustic space, warm reflection)
+ /// </summary>
+ Hall,
+
+ /// <summary>
+ /// Classic plate late reflection. (clean distinctive reverb)
+ /// </summary>
+ Plate,
+
+ /// <summary>
+ /// Cathedral late reflection. (very large acoustic space, pronounced bright reflection)
+ /// </summary>
+ Cathedral,
+
+ /// <summary>
+ /// Do not apply any delay. (max delay)
+ /// </summary>
+ NoDelay,
+
+ /// <summary>
+ /// Max delay. (used for delay line limits)
+ /// </summary>
+ Limit = NoDelay
+ }
+}
diff --git a/Ryujinx.Audio/Renderer/Common/SinkType.cs b/Ryujinx.Audio/Renderer/Common/SinkType.cs
new file mode 100644
index 00000000..e1a35508
--- /dev/null
+++ b/Ryujinx.Audio/Renderer/Common/SinkType.cs
@@ -0,0 +1,40 @@
+//
+// Copyright (c) 2019-2021 Ryujinx
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+//
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ /// <summary>
+ /// The type of a sink.
+ /// </summary>
+ public enum SinkType : byte
+ {
+ /// <summary>
+ /// The sink is in an invalid state.
+ /// </summary>
+ Invalid,
+
+ /// <summary>
+ /// The sink is a device.
+ /// </summary>
+ Device,
+
+ /// <summary>
+ /// The sink is a circular buffer.
+ /// </summary>
+ CircularBuffer
+ }
+}
diff --git a/Ryujinx.Audio/Renderer/Common/UpdateDataHeader.cs b/Ryujinx.Audio/Renderer/Common/UpdateDataHeader.cs
new file mode 100644
index 00000000..ae516662
--- /dev/null
+++ b/Ryujinx.Audio/Renderer/Common/UpdateDataHeader.cs
@@ -0,0 +1,50 @@
+//
+// Copyright (c) 2019-2021 Ryujinx
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+//
+
+using System.Runtime.CompilerServices;
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ /// <summary>
+ /// Update data header used for input and output of <see cref="Server.AudioRenderSystem.Update(System.Memory{byte}, System.Memory{byte}, System.ReadOnlyMemory{byte})"/>.
+ /// </summary>
+ public struct UpdateDataHeader
+ {
+ public int Revision;
+ public uint BehaviourSize;
+ public uint MemoryPoolsSize;
+ public uint VoicesSize;
+ public uint VoiceResourcesSize;
+ public uint EffectsSize;
+ public uint MixesSize;
+ public uint SinksSize;
+ public uint PerformanceBufferSize;
+ public uint Unknown24;
+ public uint RenderInfoSize;
+
+ private unsafe fixed int _reserved[4];
+
+ public uint TotalSize;
+
+ public void Initialize(int revision)
+ {
+ Revision = revision;
+
+ TotalSize = (uint)Unsafe.SizeOf<UpdateDataHeader>();
+ }
+ }
+}
diff --git a/Ryujinx.Audio/Renderer/Common/VoiceUpdateState.cs b/Ryujinx.Audio/Renderer/Common/VoiceUpdateState.cs
new file mode 100644
index 00000000..6cebad5e
--- /dev/null
+++ b/Ryujinx.Audio/Renderer/Common/VoiceUpdateState.cs
@@ -0,0 +1,121 @@
+//
+// Copyright (c) 2019-2021 Ryujinx
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+//
+
+using Ryujinx.Audio.Renderer.Dsp.State;
+using Ryujinx.Common.Memory;
+using Ryujinx.Common.Utilities;
+using System;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ /// <summary>
+ /// Represent the update state of a voice.
+ /// </summary>
+ /// <remarks>This is shared between the server and audio processor.</remarks>
+ [StructLayout(LayoutKind.Sequential, Pack = Align)]
+ public struct VoiceUpdateState
+ {
+ public const int Align = 0x10;
+ public const int BiquadStateOffset = 0x0;
+ public const int BiquadStateSize = 0x10;
+
+ /// <summary>
+ /// The state of the biquad filters of this voice.
+ /// </summary>
+ public Array2<BiquadFilterState> BiquadFilterState;
+
+ /// <summary>
+ /// The total amount of samples that was played.
+ /// </summary>
+ /// <remarks>This is reset to 0 when a <see cref="WaveBuffer"/> finishes playing and <see cref="WaveBuffer.IsEndOfStream"/> is set.</remarks>
+ /// <remarks>This is reset to 0 when looping while <see cref="Parameter.VoiceInParameter.DecodingBehaviour.PlayedSampleCountResetWhenLooping"/> is set.</remarks>
+ public ulong PlayedSampleCount;
+
+ /// <summary>
+ /// The current sample offset in the <see cref="WaveBuffer"/> pointed by <see cref="WaveBufferIndex"/>.
+ /// </summary>
+ public int Offset;
+
+ /// <summary>
+ /// The current index of the <see cref="WaveBuffer"/> in use.
+ /// </summary>
+ public uint WaveBufferIndex;
+
+ private WaveBufferValidArray _isWaveBufferValid;
+
+ /// <summary>
+ /// The total amount of <see cref="WaveBuffer"/> consumed.
+ /// </summary>
+ public uint WaveBufferConsumed;
+
+ /// <summary>
+ /// Pitch used for Sample Rate Conversion.
+ /// </summary>
+ public Array8<short> Pitch;
+
+ public float Fraction;
+
+ /// <summary>
+ /// The ADPCM loop context when <see cref="SampleFormat.Adpcm"/> is in use.
+ /// </summary>
+ public AdpcmLoopContext LoopContext;
+
+ /// <summary>
+ /// The last samples after a mix ramp.
+ /// </summary>
+ /// <remarks>This is used for depop (to perform voice drop).</remarks>
+ public Array24<float> LastSamples;
+
+ /// <summary>
+ /// The current count of loop performed.
+ /// </summary>
+ public int LoopCount;
+
+ [StructLayout(LayoutKind.Sequential, Size = 1 * Constants.VoiceWaveBufferCount, Pack = 1)]
+ private struct WaveBufferValidArray { }
+
+ /// <summary>
+ /// Contains information of <see cref="WaveBuffer"/> validity.
+ /// </summary>
+ public Span<bool> IsWaveBufferValid => SpanHelpers.AsSpan<WaveBufferValidArray, bool>(ref _isWaveBufferValid);
+
+ /// <summary>
+ /// Mark the current <see cref="WaveBuffer"/> as played and switch to the next one.
+ /// </summary>
+ /// <param name="waveBuffer">The current <see cref="WaveBuffer"/></param>
+ /// <param name="waveBufferIndex">The wavebuffer index.</param>
+ /// <param name="waveBufferConsumed">The amount of wavebuffers consumed.</param>
+ /// <param name="playedSampleCount">The total count of sample played.</param>
+ public void MarkEndOfBufferWaveBufferProcessing(ref WaveBuffer waveBuffer, ref int waveBufferIndex, ref uint waveBufferConsumed, ref ulong playedSampleCount)
+ {
+ IsWaveBufferValid[waveBufferIndex++] = false;
+ LoopCount = 0;
+ waveBufferConsumed++;
+
+ if (waveBufferIndex >= Constants.VoiceWaveBufferCount)
+ {
+ waveBufferIndex = 0;
+ }
+
+ if (waveBuffer.IsEndOfStream)
+ {
+ playedSampleCount = 0;
+ }
+ }
+ }
+}
diff --git a/Ryujinx.Audio/Renderer/Common/WaveBuffer.cs b/Ryujinx.Audio/Renderer/Common/WaveBuffer.cs
new file mode 100644
index 00000000..53906c0c
--- /dev/null
+++ b/Ryujinx.Audio/Renderer/Common/WaveBuffer.cs
@@ -0,0 +1,99 @@
+//
+// Copyright (c) 2019-2021 Ryujinx
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+//
+
+using System.Runtime.InteropServices;
+
+using DspAddr = System.UInt64;
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ /// <summary>
+ /// A wavebuffer used for data source commands.
+ /// </summary>
+ [StructLayout(LayoutKind.Sequential, Pack = 1)]
+ public struct WaveBuffer
+ {
+ /// <summary>
+ /// The DSP address of the sample data of the wavebuffer.
+ /// </summary>
+ public DspAddr Buffer;
+
+ /// <summary>
+ /// The DSP address of the context of the wavebuffer.
+ /// </summary>
+ /// <remarks>Only used by <see cref="SampleFormat.Adpcm"/>.</remarks>
+ public DspAddr Context;
+
+ /// <summary>
+ /// The size of the sample buffer data.
+ /// </summary>
+ public uint BufferSize;
+
+ /// <summary>
+ /// The size of the context buffer.
+ /// </summary>
+ public uint ContextSize;
+
+ /// <summary>
+ /// First sample to play on the wavebuffer.
+ /// </summary>
+ public uint StartSampleOffset;
+
+ /// <summary>
+ /// Last sample to play on the wavebuffer.
+ /// </summary>
+ public uint EndSampleOffset;
+
+ /// <summary>
+ /// First sample to play when looping the wavebuffer.
+ /// </summary>
+ /// <remarks>
+ /// If <see cref="LoopStartSampleOffset"/> or <see cref="LoopEndSampleOffset"/> is equal to zero,, it will default to <see cref="StartSampleOffset"/> and <see cref="EndSampleOffset"/>.
+ /// </remarks>
+ public uint LoopStartSampleOffset;
+
+ /// <summary>
+ /// Last sample to play when looping the wavebuffer.
+ /// </summary>
+ /// <remarks>
+ /// If <see cref="LoopStartSampleOffset"/> or <see cref="LoopEndSampleOffset"/> is equal to zero, it will default to <see cref="StartSampleOffset"/> and <see cref="EndSampleOffset"/>.
+ /// </remarks>
+ public uint LoopEndSampleOffset;
+
+ /// <summary>
+ /// The max loop count.
+ /// </summary>
+ public int LoopCount;
+
+ /// <summary>
+ /// Set to true if the wavebuffer is looping.
+ /// </summary>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool Looping;
+
+ /// <summary>
+ /// Set to true if the wavebuffer is the end of stream.
+ /// </summary>
+ [MarshalAs(UnmanagedType.I1)]
+ public bool IsEndOfStream;
+
+ /// <summary>
+ /// Padding/Reserved.
+ /// </summary>
+ private ushort _padding;
+ }
+}
diff --git a/Ryujinx.Audio/Renderer/Common/WorkBufferAllocator.cs b/Ryujinx.Audio/Renderer/Common/WorkBufferAllocator.cs
new file mode 100644
index 00000000..2aff4eb0
--- /dev/null
+++ b/Ryujinx.Audio/Renderer/Common/WorkBufferAllocator.cs
@@ -0,0 +1,78 @@
+//
+// Copyright (c) 2019-2021 Ryujinx
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Lesser General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public License
+// along with this program. If not, see <https://www.gnu.org/licenses/>.
+//
+
+using Ryujinx.Audio.Renderer.Utils;
+using Ryujinx.Common;
+using System;
+using System.Diagnostics;
+using System.Runtime.CompilerServices;
+
+namespace Ryujinx.Audio.Renderer.Common
+{
+ public class WorkBufferAllocator
+ {
+ public Memory<byte> BackingMemory { get; }
+
+ public ulong Offset { get; private set; }
+
+ public WorkBufferAllocator(Memory<byte> backingMemory)
+ {
+ BackingMemory = backingMemory;
+ }
+
+ public Memory<byte> Allocate(ulong size, int align)
+ {
+ Debug.Assert(align != 0);
+
+ if (size != 0)
+ {
+ ulong alignedOffset = BitUtils.AlignUp(Offset, align);
+
+ if (alignedOffset + size <= (ulong)BackingMemory.Length)
+ {
+ Memory<byte> result = BackingMemory.Slice((int)alignedOffset, (int)size);
+
+ Offset = alignedOffset + size;
+
+ // Clear the memory to be sure that is does not contain any garbage.
+ result.Span.Fill(0);
+
+ return result;
+ }
+ }
+
+ return Memory<byte>.Empty;
+ }
+
+ public Memory<T> Allocate<T>(ulong count, int align) where T: unmanaged
+ {
+ Memory<byte> allocatedMemory = Allocate((ulong)Unsafe.SizeOf<T>() * count, align);
+
+ if (allocatedMemory.IsEmpty)
+ {
+ return Memory<T>.Empty;
+ }
+
+ return SpanMemoryManager<T>.Cast(allocatedMemory);
+ }
+
+ public static ulong GetTargetSize<T>(ulong currentSize, ulong count, int align) where T: unmanaged
+ {
+ return BitUtils.AlignUp(currentSize, align) + (ulong)Unsafe.SizeOf<T>() * count;
+ }
+ }
+}