Jelajahi Sumber

Allocate work buffer for audio renderer instead of using guest supplied memory (#3276)

* Allocate work buffer for audio renderer instead of using guest supplied memory

* Typo

* Use GC.AllocateArray to allocate pinned array
gdkchan 3 tahun lalu
induk
melakukan
81f1a4dc31

+ 12 - 7
Ryujinx.Audio/Renderer/Server/AudioRenderSystem.cs

@@ -55,7 +55,6 @@ namespace Ryujinx.Audio.Renderer.Server
         private uint _processHandle;
         private ulong _appletResourceId;
 
-        private WritableRegion _workBufferRegion;
         private MemoryHandle _workBufferMemoryPin;
 
         private Memory<float> _mixBuffer;
@@ -98,7 +97,15 @@ namespace Ryujinx.Audio.Renderer.Server
             _sessionId = 0;
         }
 
-        public ResultCode Initialize(ref AudioRendererConfiguration parameter, uint processHandle, CpuAddress workBuffer, ulong workBufferSize, int sessionId, ulong appletResourceId, IVirtualMemoryManager memoryManager)
+        public ResultCode Initialize(
+            ref AudioRendererConfiguration parameter,
+            uint processHandle,
+            Memory<byte> workBufferMemory,
+            CpuAddress workBuffer,
+            ulong workBufferSize,
+            int sessionId,
+            ulong appletResourceId,
+            IVirtualMemoryManager memoryManager)
         {
             if (!BehaviourContext.CheckValidRevision(parameter.Revision))
             {
@@ -134,11 +141,10 @@ namespace Ryujinx.Audio.Renderer.Server
 
             WorkBufferAllocator workBufferAllocator;
 
-            _workBufferRegion = MemoryManager.GetWritableRegion(workBuffer, (int)workBufferSize);
-            _workBufferRegion.Memory.Span.Fill(0);
-            _workBufferMemoryPin = _workBufferRegion.Memory.Pin();
+            workBufferMemory.Span.Fill(0);
+            _workBufferMemoryPin = workBufferMemory.Pin();
 
-            workBufferAllocator = new WorkBufferAllocator(_workBufferRegion.Memory);
+            workBufferAllocator = new WorkBufferAllocator(workBufferMemory);
 
             PoolMapper poolMapper = new PoolMapper(processHandle, false);
             poolMapper.InitializeSystemPool(ref _dspMemoryPoolState, workBuffer, workBufferSize);
@@ -841,7 +847,6 @@ namespace Ryujinx.Audio.Renderer.Server
                 _manager.Unregister(this);
                 _terminationEvent.Dispose();
                 _workBufferMemoryPin.Dispose();
-                _workBufferRegion.Dispose();
 
                 if (MemoryManager is IRefCounted rc)
                 {

+ 23 - 2
Ryujinx.Audio/Renderer/Server/AudioRendererManager.cs

@@ -305,13 +305,34 @@ namespace Ryujinx.Audio.Renderer.Server
         /// <param name="workBufferSize">The guest work buffer size.</param>
         /// <param name="processHandle">The process handle of the application.</param>
         /// <returns>A <see cref="ResultCode"/> reporting an error or a success.</returns>
-        public ResultCode OpenAudioRenderer(out AudioRenderSystem renderer, IVirtualMemoryManager memoryManager, ref AudioRendererConfiguration parameter, ulong appletResourceUserId, ulong workBufferAddress, ulong workBufferSize, uint processHandle, float volume)
+        public ResultCode OpenAudioRenderer(
+            out AudioRenderSystem renderer,
+            IVirtualMemoryManager memoryManager,
+            ref AudioRendererConfiguration parameter,
+            ulong appletResourceUserId,
+            ulong workBufferAddress,
+            ulong workBufferSize,
+            uint processHandle,
+            float volume)
         {
             int sessionId = AcquireSessionId();
 
             AudioRenderSystem audioRenderer = new AudioRenderSystem(this, _sessionsSystemEvent[sessionId]);
 
-            ResultCode result = audioRenderer.Initialize(ref parameter, processHandle, workBufferAddress, workBufferSize, sessionId, appletResourceUserId, memoryManager);
+            // TODO: Eventually, we should try to use the guest supplied work buffer instead of allocating
+            // our own. However, it was causing problems on some applications that would unmap the memory
+            // before the audio renderer was fully disposed.
+            Memory<byte> workBufferMemory = GC.AllocateArray<byte>((int)workBufferSize, pinned: true);
+
+            ResultCode result = audioRenderer.Initialize(
+                ref parameter,
+                processHandle,
+                workBufferMemory,
+                workBufferAddress,
+                workBufferSize,
+                sessionId,
+                appletResourceUserId,
+                memoryManager);
 
             if (result == ResultCode.Success)
             {

+ 17 - 2
Ryujinx.HLE/HOS/Services/Audio/AudioRendererManager.cs

@@ -31,11 +31,26 @@ namespace Ryujinx.HLE.HOS.Services.Audio
             return AudioRendererManagerImpl.GetWorkBufferSize(ref parameter);
         }
 
-        public ResultCode OpenAudioRenderer(ServiceCtx context, out IAudioRenderer obj, ref AudioRendererConfiguration parameter, ulong workBufferSize, ulong appletResourceUserId, KTransferMemory workBufferTransferMemory, uint processHandle)
+        public ResultCode OpenAudioRenderer(
+            ServiceCtx context,
+            out IAudioRenderer obj,
+            ref AudioRendererConfiguration parameter,
+            ulong workBufferSize,
+            ulong appletResourceUserId,
+            KTransferMemory workBufferTransferMemory,
+            uint processHandle)
         {
             var memoryManager = context.Process.HandleTable.GetKProcess((int)processHandle).CpuMemory;
 
-            ResultCode result = (ResultCode)_impl.OpenAudioRenderer(out AudioRenderSystem renderer, memoryManager, ref parameter, appletResourceUserId, workBufferTransferMemory.Address, workBufferTransferMemory.Size, processHandle, context.Device.Configuration.AudioVolume);
+            ResultCode result = (ResultCode)_impl.OpenAudioRenderer(
+                out AudioRenderSystem renderer,
+                memoryManager,
+                ref parameter,
+                appletResourceUserId,
+                workBufferTransferMemory.Address,
+                workBufferTransferMemory.Size,
+                processHandle,
+                context.Device.Configuration.AudioVolume);
 
             if (result == ResultCode.Success)
             {

+ 8 - 1
Ryujinx.HLE/HOS/Services/Audio/AudioRendererManagerServer.cs

@@ -34,7 +34,14 @@ namespace Ryujinx.HLE.HOS.Services.Audio
             KTransferMemory workBufferTransferMemory = context.Process.HandleTable.GetObject<KTransferMemory>(transferMemoryHandle);
             uint processHandle = (uint)context.Request.HandleDesc.ToCopy[1];
 
-            ResultCode result = _impl.OpenAudioRenderer(context, out IAudioRenderer renderer, ref parameter, workBufferSize, appletResourceUserId, workBufferTransferMemory, processHandle);
+            ResultCode result = _impl.OpenAudioRenderer(
+                context,
+                out IAudioRenderer renderer,
+                ref parameter,
+                workBufferSize,
+                appletResourceUserId,
+                workBufferTransferMemory,
+                processHandle);
 
             if (result == ResultCode.Success)
             {