From cee712105850ac3385cd0091a923438167433f9f Mon Sep 17 00:00:00 2001 From: TSR Berry <20988865+TSRBerry@users.noreply.github.com> Date: Sat, 8 Apr 2023 01:22:00 +0200 Subject: Move solution and projects to src --- .../Renderer/Server/MemoryPool/AddressInfo.cs | 133 ++++++++ .../Renderer/Server/MemoryPool/MemoryPoolState.cs | 130 ++++++++ .../Renderer/Server/MemoryPool/PoolMapper.cs | 366 +++++++++++++++++++++ 3 files changed, 629 insertions(+) create mode 100644 src/Ryujinx.Audio/Renderer/Server/MemoryPool/AddressInfo.cs create mode 100644 src/Ryujinx.Audio/Renderer/Server/MemoryPool/MemoryPoolState.cs create mode 100644 src/Ryujinx.Audio/Renderer/Server/MemoryPool/PoolMapper.cs (limited to 'src/Ryujinx.Audio/Renderer/Server/MemoryPool') diff --git a/src/Ryujinx.Audio/Renderer/Server/MemoryPool/AddressInfo.cs b/src/Ryujinx.Audio/Renderer/Server/MemoryPool/AddressInfo.cs new file mode 100644 index 00000000..5fd6b2b9 --- /dev/null +++ b/src/Ryujinx.Audio/Renderer/Server/MemoryPool/AddressInfo.cs @@ -0,0 +1,133 @@ +using System; +using System.Runtime.InteropServices; +using CpuAddress = System.UInt64; +using DspAddress = System.UInt64; + +namespace Ryujinx.Audio.Renderer.Server.MemoryPool +{ + /// + /// Represents the information of a region shared between the CPU and DSP. + /// + public struct AddressInfo + { + /// + /// The target CPU address of the region. + /// + public CpuAddress CpuAddress; + + /// + /// The size of the region. + /// + public ulong Size; + + private unsafe MemoryPoolState* _memoryPools; + + /// + /// The forced DSP address of the region. + /// + public DspAddress ForceMappedDspAddress; + + private unsafe ref MemoryPoolState MemoryPoolState => ref *_memoryPools; + + public unsafe bool HasMemoryPoolState => (IntPtr)_memoryPools != IntPtr.Zero; + + /// + /// Create an new empty . + /// + /// A new empty . + public static AddressInfo Create() + { + return Create(0, 0); + } + + /// + /// Create a new . + /// + /// The target of the region. + /// The target size of the region. + /// A new . + public static AddressInfo Create(CpuAddress cpuAddress, ulong size) + { + unsafe + { + return new AddressInfo + { + CpuAddress = cpuAddress, + _memoryPools = MemoryPoolState.Null, + Size = size, + ForceMappedDspAddress = 0 + }; + } + } + + /// + /// Setup the CPU address and size of the . + /// + /// The target of the region. + /// The size of the region. + public void Setup(CpuAddress cpuAddress, ulong size) + { + CpuAddress = cpuAddress; + Size = size; + ForceMappedDspAddress = 0; + + unsafe + { + _memoryPools = MemoryPoolState.Null; + } + } + + /// + /// Set the associated. + /// + /// The associated. + public void SetupMemoryPool(Span memoryPoolState) + { + unsafe + { + fixed (MemoryPoolState* ptr = &MemoryMarshal.GetReference(memoryPoolState)) + { + SetupMemoryPool(ptr); + } + } + } + + /// + /// Set the associated. + /// + /// The associated. + public unsafe void SetupMemoryPool(MemoryPoolState* memoryPoolState) + { + _memoryPools = memoryPoolState; + } + + /// + /// Check if the is mapped. + /// + /// Returns true if the is mapped. + public bool HasMappedMemoryPool() + { + return HasMemoryPoolState && MemoryPoolState.IsMapped(); + } + + /// + /// Get the DSP address associated to the . + /// + /// If true, mark the as used. + /// Returns the DSP address associated to the . + public DspAddress GetReference(bool markUsed) + { + if (!HasMappedMemoryPool()) + { + return ForceMappedDspAddress; + } + + if (markUsed) + { + MemoryPoolState.IsUsed = true; + } + + return MemoryPoolState.Translate(CpuAddress, Size); + } + } +} \ No newline at end of file diff --git a/src/Ryujinx.Audio/Renderer/Server/MemoryPool/MemoryPoolState.cs b/src/Ryujinx.Audio/Renderer/Server/MemoryPool/MemoryPoolState.cs new file mode 100644 index 00000000..69466bab --- /dev/null +++ b/src/Ryujinx.Audio/Renderer/Server/MemoryPool/MemoryPoolState.cs @@ -0,0 +1,130 @@ +using System; +using System.Runtime.InteropServices; +using CpuAddress = System.UInt64; +using DspAddress = System.UInt64; + +namespace Ryujinx.Audio.Renderer.Server.MemoryPool +{ + /// + /// Server state for a memory pool. + /// + [StructLayout(LayoutKind.Sequential, Size = 0x20, Pack = Alignment)] + public struct MemoryPoolState + { + public const int Alignment = 0x10; + + /// + /// The location of the . + /// + public enum LocationType : uint + { + /// + /// located on the CPU side for user use. + /// + Cpu, + + /// + /// located on the DSP side for system use. + /// + Dsp + } + + /// + /// The CPU address associated to the . + /// + public CpuAddress CpuAddress; + + /// + /// The DSP address associated to the . + /// + public DspAddress DspAddress; + + /// + /// The size associated to the . + /// + public ulong Size; + + /// + /// The associated to the . + /// + public LocationType Location; + + /// + /// Set to true if the is used. + /// + [MarshalAs(UnmanagedType.I1)] + public bool IsUsed; + + public static unsafe MemoryPoolState* Null => (MemoryPoolState*)IntPtr.Zero.ToPointer(); + + /// + /// Create a new with the given . + /// + /// The location type to use. + /// A new with the given . + public static MemoryPoolState Create(LocationType location) + { + return new MemoryPoolState + { + CpuAddress = 0, + DspAddress = 0, + Size = 0, + Location = location + }; + } + + /// + /// Set the and size of the . + /// + /// The . + /// The size. + public void SetCpuAddress(CpuAddress cpuAddress, ulong size) + { + CpuAddress = cpuAddress; + Size = size; + } + + /// + /// Check if the given and size is contains in the . + /// + /// The . + /// The size. + /// True if the is contained inside the . + public bool Contains(CpuAddress targetCpuAddress, ulong size) + { + if (CpuAddress <= targetCpuAddress && size + targetCpuAddress <= Size + CpuAddress) + { + return true; + } + + return false; + } + + /// + /// Translate the given CPU address to a DSP address. + /// + /// The . + /// The size. + /// the target DSP address. + public DspAddress Translate(CpuAddress targetCpuAddress, ulong size) + { + if (Contains(targetCpuAddress, size) && IsMapped()) + { + ulong offset = targetCpuAddress - CpuAddress; + + return DspAddress + offset; + } + + return 0; + } + + /// + /// Is the mapped on the DSP? + /// + /// Returns true if the is mapped on the DSP. + public bool IsMapped() + { + return DspAddress != 0; + } + } +} \ No newline at end of file diff --git a/src/Ryujinx.Audio/Renderer/Server/MemoryPool/PoolMapper.cs b/src/Ryujinx.Audio/Renderer/Server/MemoryPool/PoolMapper.cs new file mode 100644 index 00000000..6c79da15 --- /dev/null +++ b/src/Ryujinx.Audio/Renderer/Server/MemoryPool/PoolMapper.cs @@ -0,0 +1,366 @@ +using Ryujinx.Audio.Renderer.Common; +using Ryujinx.Audio.Renderer.Parameter; +using Ryujinx.Audio.Renderer.Utils; +using Ryujinx.Common.Logging; +using System; +using static Ryujinx.Audio.Renderer.Common.BehaviourParameter; + +using CpuAddress = System.UInt64; +using DspAddress = System.UInt64; + +namespace Ryujinx.Audio.Renderer.Server.MemoryPool +{ + /// + /// Memory pool mapping helper. + /// + public class PoolMapper + { + const uint CurrentProcessPseudoHandle = 0xFFFF8001; + + /// + /// The result of . + /// + public enum UpdateResult : uint + { + /// + /// No error reported. + /// + Success = 0, + + /// + /// The user parameters were invalid. + /// + InvalidParameter = 1, + + /// + /// mapping failed. + /// + MapError = 2, + + /// + /// unmapping failed. + /// + UnmapError = 3 + } + + /// + /// The handle of the process owning the CPU memory manipulated. + /// + private uint _processHandle; + + /// + /// The that will be manipulated. + /// + private Memory _memoryPools; + + /// + /// If set to true, this will try to force map memory pool even if their state are considered invalid. + /// + private bool _isForceMapEnabled; + + /// + /// Create a new used for system mapping. + /// + /// The handle of the process owning the CPU memory manipulated. + /// If set to true, this will try to force map memory pool even if their state are considered invalid. + public PoolMapper(uint processHandle, bool isForceMapEnabled) + { + _processHandle = processHandle; + _isForceMapEnabled = isForceMapEnabled; + _memoryPools = Memory.Empty; + } + + /// + /// Create a new used for user mapping. + /// + /// The handle of the process owning the CPU memory manipulated. + /// The user memory pools. + /// If set to true, this will try to force map memory pool even if their state are considered invalid. + public PoolMapper(uint processHandle, Memory memoryPool, bool isForceMapEnabled) + { + _processHandle = processHandle; + _memoryPools = memoryPool; + _isForceMapEnabled = isForceMapEnabled; + } + + /// + /// Initialize the for system use. + /// + /// The for system use. + /// The to assign. + /// The size to assign. + /// Returns true if mapping on the succeeded. + public bool InitializeSystemPool(ref MemoryPoolState memoryPool, CpuAddress cpuAddress, ulong size) + { + if (memoryPool.Location != MemoryPoolState.LocationType.Dsp) + { + return false; + } + + return InitializePool(ref memoryPool, cpuAddress, size); + } + + /// + /// Initialize the . + /// + /// The . + /// The to assign. + /// The size to assign. + /// Returns true if mapping on the succeeded. + public bool InitializePool(ref MemoryPoolState memoryPool, CpuAddress cpuAddress, ulong size) + { + memoryPool.SetCpuAddress(cpuAddress, size); + + return Map(ref memoryPool) != 0; + } + + /// + /// Get the process handle associated to the . + /// + /// The . + /// Returns the process handle associated to the . + public uint GetProcessHandle(ref MemoryPoolState memoryPool) + { + if (memoryPool.Location == MemoryPoolState.LocationType.Cpu) + { + return CurrentProcessPseudoHandle; + } + else if (memoryPool.Location == MemoryPoolState.LocationType.Dsp) + { + return _processHandle; + } + + return 0; + } + + /// + /// Map the on the . + /// + /// The to map. + /// Returns the DSP address mapped. + public DspAddress Map(ref MemoryPoolState memoryPool) + { + DspAddress result = AudioProcessorMemoryManager.Map(GetProcessHandle(ref memoryPool), memoryPool.CpuAddress, memoryPool.Size); + + if (result != 0) + { + memoryPool.DspAddress = result; + } + + return result; + } + + /// + /// Unmap the from the . + /// + /// The to unmap. + /// Returns true if unmapped. + public bool Unmap(ref MemoryPoolState memoryPool) + { + if (memoryPool.IsUsed) + { + return false; + } + + AudioProcessorMemoryManager.Unmap(GetProcessHandle(ref memoryPool), memoryPool.CpuAddress, memoryPool.Size); + + memoryPool.SetCpuAddress(0, 0); + memoryPool.DspAddress = 0; + + return true; + } + + /// + /// Find a associated to the region given. + /// + /// The region . + /// The region size. + /// Returns the found or if not found. + private Span FindMemoryPool(CpuAddress cpuAddress, ulong size) + { + if (!_memoryPools.IsEmpty && _memoryPools.Length > 0) + { + for (int i = 0; i < _memoryPools.Length; i++) + { + if (_memoryPools.Span[i].Contains(cpuAddress, size)) + { + return _memoryPools.Span.Slice(i, 1); + } + } + } + + return Span.Empty; + } + + /// + /// Force unmap the given . + /// + /// The to force unmap + public void ForceUnmap(ref AddressInfo addressInfo) + { + if (_isForceMapEnabled) + { + Span memoryPool = FindMemoryPool(addressInfo.CpuAddress, addressInfo.Size); + + if (!memoryPool.IsEmpty) + { + AudioProcessorMemoryManager.Unmap(_processHandle, memoryPool[0].CpuAddress, memoryPool[0].Size); + + return; + } + + AudioProcessorMemoryManager.Unmap(_processHandle, addressInfo.CpuAddress, 0); + } + } + + /// + /// Try to attach the given region to the . + /// + /// The error information if an error was generated. + /// The to attach the region to. + /// The region . + /// The region size. + /// Returns true if mapping was performed. + public bool TryAttachBuffer(out ErrorInfo errorInfo, ref AddressInfo addressInfo, CpuAddress cpuAddress, ulong size) + { + errorInfo = new ErrorInfo(); + + addressInfo.Setup(cpuAddress, size); + + if (AssignDspAddress(ref addressInfo)) + { + errorInfo.ErrorCode = 0x0; + errorInfo.ExtraErrorInfo = 0x0; + + return true; + } + else + { + errorInfo.ErrorCode = ResultCode.InvalidAddressInfo; + errorInfo.ExtraErrorInfo = addressInfo.CpuAddress; + + return _isForceMapEnabled; + } + } + + /// + /// Update a using user parameters. + /// + /// The to update. + /// Input user parameter. + /// Output user parameter. + /// Returns the of the operations performed. + public UpdateResult Update(ref MemoryPoolState memoryPool, ref MemoryPoolInParameter inParameter, ref MemoryPoolOutStatus outStatus) + { + MemoryPoolUserState inputState = inParameter.State; + + MemoryPoolUserState outputState; + + const uint pageSize = 0x1000; + + if (inputState != MemoryPoolUserState.RequestAttach && inputState != MemoryPoolUserState.RequestDetach) + { + return UpdateResult.Success; + } + + if (inParameter.CpuAddress == 0 || (inParameter.CpuAddress % pageSize) != 0) + { + return UpdateResult.InvalidParameter; + } + + if (inParameter.Size == 0 || (inParameter.Size % pageSize) != 0) + { + return UpdateResult.InvalidParameter; + } + + if (inputState == MemoryPoolUserState.RequestAttach) + { + bool initializeSuccess = InitializePool(ref memoryPool, inParameter.CpuAddress, inParameter.Size); + + if (!initializeSuccess) + { + memoryPool.SetCpuAddress(0, 0); + + Logger.Error?.Print(LogClass.AudioRenderer, $"Map of memory pool (address: 0x{inParameter.CpuAddress:x}, size 0x{inParameter.Size:x}) failed!"); + return UpdateResult.MapError; + } + + outputState = MemoryPoolUserState.Attached; + } + else + { + if (memoryPool.CpuAddress != inParameter.CpuAddress || memoryPool.Size != inParameter.Size) + { + return UpdateResult.InvalidParameter; + } + + if (!Unmap(ref memoryPool)) + { + Logger.Error?.Print(LogClass.AudioRenderer, $"Unmap of memory pool (address: 0x{memoryPool.CpuAddress:x}, size 0x{memoryPool.Size:x}) failed!"); + return UpdateResult.UnmapError; + } + + outputState = MemoryPoolUserState.Detached; + } + + outStatus.State = outputState; + + return UpdateResult.Success; + } + + /// + /// Map the to the . + /// + /// The to map. + /// Returns true if mapping was performed. + private bool AssignDspAddress(ref AddressInfo addressInfo) + { + if (addressInfo.CpuAddress == 0) + { + return false; + } + + if (_memoryPools.Length > 0) + { + Span memoryPool = FindMemoryPool(addressInfo.CpuAddress, addressInfo.Size); + + if (!memoryPool.IsEmpty) + { + addressInfo.SetupMemoryPool(memoryPool); + + return true; + } + } + + if (_isForceMapEnabled) + { + DspAddress dspAddress = AudioProcessorMemoryManager.Map(_processHandle, addressInfo.CpuAddress, addressInfo.Size); + + addressInfo.ForceMappedDspAddress = dspAddress; + + AudioProcessorMemoryManager.Map(_processHandle, addressInfo.CpuAddress, addressInfo.Size); + } + else + { + unsafe + { + addressInfo.SetupMemoryPool(MemoryPoolState.Null); + } + } + + return false; + } + + /// + /// Remove the usage flag from all the . + /// + /// The to reset. + public static void ClearUsageState(Memory memoryPool) + { + foreach (ref MemoryPoolState info in memoryPool.Span) + { + info.IsUsed = false; + } + } + } +} \ No newline at end of file -- cgit v1.2.3