From f4f496cb48a59aae36e3252baa90396e1bfadd2e Mon Sep 17 00:00:00 2001 From: gdkchan Date: Tue, 28 Sep 2021 19:43:40 -0300 Subject: NVDEC (H264): Use separate contexts per channel and decode frames in DTS order (#2671) * Use separate NVDEC contexts per channel (for FFMPEG) * Remove NVDEC -> VIC frame override hack * Add missing bottom_field_pic_order_in_frame_present_flag * Make FFMPEG logging static * nit: Remove empty lines * New FFMPEG decoding approach -- call h264_decode_frame directly, trim surface cache to reduce memory usage * Fix case * Silence warnings * PR feedback * Per-decoder rather than per-codec ownership of surfaces on the cache --- Ryujinx.Graphics.Host1x/Host1xDevice.cs | 61 ++++++++++++++++++++++++++++++--- Ryujinx.Graphics.Host1x/ThiDevice.cs | 53 ++++++++++++++++++++++++---- 2 files changed, 103 insertions(+), 11 deletions(-) (limited to 'Ryujinx.Graphics.Host1x') diff --git a/Ryujinx.Graphics.Host1x/Host1xDevice.cs b/Ryujinx.Graphics.Host1x/Host1xDevice.cs index 7f6cef62..61408fc4 100644 --- a/Ryujinx.Graphics.Host1x/Host1xDevice.cs +++ b/Ryujinx.Graphics.Host1x/Host1xDevice.cs @@ -9,8 +9,20 @@ namespace Ryujinx.Graphics.Host1x { public sealed class Host1xDevice : IDisposable { + private struct Command + { + public int[] Buffer { get; } + public long ContextId { get; } + + public Command(int[] buffer, long contextId) + { + Buffer = buffer; + ContextId = contextId; + } + } + private readonly SyncptIncrManager _syncptIncrMgr; - private readonly AsyncWorkQueue _commandQueue; + private readonly AsyncWorkQueue _commandQueue; private readonly Devices _devices = new Devices(); @@ -26,7 +38,7 @@ namespace Ryujinx.Graphics.Host1x public Host1xDevice(SynchronizationManager syncMgr) { _syncptIncrMgr = new SyncptIncrManager(syncMgr); - _commandQueue = new AsyncWorkQueue(Process, "Ryujinx.Host1xProcessor"); + _commandQueue = new AsyncWorkQueue(Process, "Ryujinx.Host1xProcessor"); Class = new Host1xClass(syncMgr); @@ -39,13 +51,52 @@ namespace Ryujinx.Graphics.Host1x _devices.RegisterDevice(classId, thi); } - public void Submit(ReadOnlySpan commandBuffer) + public long CreateContext() { - _commandQueue.Add(commandBuffer.ToArray()); + if (_devices.GetDevice(ClassId.Nvdec) is IDeviceStateWithContext nvdec) + { + return nvdec.CreateContext(); + } + + return -1; } - private void Process(int[] commandBuffer) + public void DestroyContext(long id) { + if (id == -1) + { + return; + } + + if (_devices.GetDevice(ClassId.Nvdec) is IDeviceStateWithContext nvdec) + { + nvdec.DestroyContext(id); + } + } + + private void SetNvdecContext(long id) + { + if (id == -1) + { + return; + } + + if (_devices.GetDevice(ClassId.Nvdec) is IDeviceStateWithContext nvdec) + { + nvdec.BindContext(id); + } + } + + public void Submit(ReadOnlySpan commandBuffer, long contextId) + { + _commandQueue.Add(new Command(commandBuffer.ToArray(), contextId)); + } + + private void Process(Command command) + { + SetNvdecContext(command.ContextId); + int[] commandBuffer = command.Buffer; + for (int index = 0; index < commandBuffer.Length; index++) { Step(commandBuffer[index]); diff --git a/Ryujinx.Graphics.Host1x/ThiDevice.cs b/Ryujinx.Graphics.Host1x/ThiDevice.cs index 8e3e11b0..114ee26e 100644 --- a/Ryujinx.Graphics.Host1x/ThiDevice.cs +++ b/Ryujinx.Graphics.Host1x/ThiDevice.cs @@ -5,19 +5,24 @@ using System.Collections.Generic; namespace Ryujinx.Graphics.Host1x { - class ThiDevice : IDeviceState, IDisposable + class ThiDevice : IDeviceStateWithContext, IDisposable { private readonly ClassId _classId; private readonly IDeviceState _device; private readonly SyncptIncrManager _syncptIncrMgr; + private long _currentContextId; + private long _previousContextId; + private class CommandAction { + public long ContextId { get; } public int Data { get; } - public CommandAction(int data) + public CommandAction(long contextId, int data) { + ContextId = contextId; Data = data; } } @@ -26,7 +31,7 @@ namespace Ryujinx.Graphics.Host1x { public int Method { get; } - public MethodCallAction(int method, int data) : base(data) + public MethodCallAction(long contextId, int method, int data) : base(contextId, data) { Method = method; } @@ -34,7 +39,7 @@ namespace Ryujinx.Graphics.Host1x private class SyncptIncrAction : CommandAction { - public SyncptIncrAction(uint syncptIncrHandle) : base((int)syncptIncrHandle) + public SyncptIncrAction(long contextId, uint syncptIncrHandle) : base(contextId, (int)syncptIncrHandle) { } } @@ -54,6 +59,31 @@ namespace Ryujinx.Graphics.Host1x { nameof(ThiRegisters.IncrSyncpt), new RwCallback(IncrSyncpt, null) }, { nameof(ThiRegisters.Method1), new RwCallback(Method1, null) } }); + + _previousContextId = -1; + } + + public long CreateContext() + { + if (_device is IDeviceStateWithContext deviceWithContext) + { + return deviceWithContext.CreateContext(); + } + + return -1; + } + + public void DestroyContext(long id) + { + if (_device is IDeviceStateWithContext deviceWithContext) + { + deviceWithContext.DestroyContext(id); + } + } + + public void BindContext(long id) + { + _currentContextId = id; } public int Read(int offset) => _state.Read(offset); @@ -70,17 +100,28 @@ namespace Ryujinx.Graphics.Host1x } else { - _commandQueue.Add(new SyncptIncrAction(_syncptIncrMgr.IncrementWhenDone(_classId, syncpointId))); + _commandQueue.Add(new SyncptIncrAction(_currentContextId, _syncptIncrMgr.IncrementWhenDone(_classId, syncpointId))); } } private void Method1(int data) { - _commandQueue.Add(new MethodCallAction((int)_state.State.Method0 * 4, data)); + _commandQueue.Add(new MethodCallAction(_currentContextId, (int)_state.State.Method0 * 4, data)); } private void Process(CommandAction cmdAction) { + long contextId = cmdAction.ContextId; + if (contextId != _previousContextId) + { + _previousContextId = contextId; + + if (_device is IDeviceStateWithContext deviceWithContext) + { + deviceWithContext.BindContext(contextId); + } + } + if (cmdAction is SyncptIncrAction syncptIncrAction) { _syncptIncrMgr.SignalDone((uint)syncptIncrAction.Data); -- cgit v1.2.3