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
This commit is contained in:
@ -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<int[]> _commandQueue;
|
||||
private readonly AsyncWorkQueue<Command> _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<int[]>(Process, "Ryujinx.Host1xProcessor");
|
||||
_commandQueue = new AsyncWorkQueue<Command>(Process, "Ryujinx.Host1xProcessor");
|
||||
|
||||
Class = new Host1xClass(syncMgr);
|
||||
|
||||
@ -39,13 +51,52 @@ namespace Ryujinx.Graphics.Host1x
|
||||
_devices.RegisterDevice(classId, thi);
|
||||
}
|
||||
|
||||
public void Submit(ReadOnlySpan<int> 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<int> 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]);
|
||||
|
@ -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);
|
||||
|
Reference in New Issue
Block a user