mirror of
https://github.com/Ryujinx/Ryujinx.git
synced 2024-08-20 23:58:42 +02:00
* 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
175 lines
4.7 KiB
C#
175 lines
4.7 KiB
C#
using Ryujinx.Common;
|
|
using Ryujinx.Common.Logging;
|
|
using Ryujinx.Graphics.Device;
|
|
using Ryujinx.Graphics.Gpu.Synchronization;
|
|
using System;
|
|
using System.Numerics;
|
|
|
|
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<Command> _commandQueue;
|
|
|
|
private readonly Devices _devices = new Devices();
|
|
|
|
public Host1xClass Class { get; }
|
|
|
|
private IDeviceState _device;
|
|
|
|
private int _count;
|
|
private int _offset;
|
|
private int _mask;
|
|
private bool _incrementing;
|
|
|
|
public Host1xDevice(SynchronizationManager syncMgr)
|
|
{
|
|
_syncptIncrMgr = new SyncptIncrManager(syncMgr);
|
|
_commandQueue = new AsyncWorkQueue<Command>(Process, "Ryujinx.Host1xProcessor");
|
|
|
|
Class = new Host1xClass(syncMgr);
|
|
|
|
_devices.RegisterDevice(ClassId.Host1x, Class);
|
|
}
|
|
|
|
public void RegisterDevice(ClassId classId, IDeviceState device)
|
|
{
|
|
var thi = new ThiDevice(classId, device ?? throw new ArgumentNullException(nameof(device)), _syncptIncrMgr);
|
|
_devices.RegisterDevice(classId, thi);
|
|
}
|
|
|
|
public long CreateContext()
|
|
{
|
|
if (_devices.GetDevice(ClassId.Nvdec) is IDeviceStateWithContext nvdec)
|
|
{
|
|
return nvdec.CreateContext();
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
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]);
|
|
}
|
|
}
|
|
|
|
private void Step(int value)
|
|
{
|
|
if (_mask != 0)
|
|
{
|
|
int lbs = BitOperations.TrailingZeroCount(_mask);
|
|
|
|
_mask &= ~(1 << lbs);
|
|
|
|
DeviceWrite(_offset + lbs, value);
|
|
|
|
return;
|
|
}
|
|
else if (_count != 0)
|
|
{
|
|
_count--;
|
|
|
|
DeviceWrite(_offset, value);
|
|
|
|
if (_incrementing)
|
|
{
|
|
_offset++;
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
OpCode opCode = (OpCode)((value >> 28) & 0xf);
|
|
|
|
switch (opCode)
|
|
{
|
|
case OpCode.SetClass:
|
|
_mask = value & 0x3f;
|
|
ClassId classId = (ClassId)((value >> 6) & 0x3ff);
|
|
_offset = (value >> 16) & 0xfff;
|
|
_device = _devices.GetDevice(classId);
|
|
break;
|
|
case OpCode.Incr:
|
|
case OpCode.NonIncr:
|
|
_count = value & 0xffff;
|
|
_offset = (value >> 16) & 0xfff;
|
|
_incrementing = opCode == OpCode.Incr;
|
|
break;
|
|
case OpCode.Mask:
|
|
_mask = value & 0xffff;
|
|
_offset = (value >> 16) & 0xfff;
|
|
break;
|
|
case OpCode.Imm:
|
|
int data = value & 0xfff;
|
|
_offset = (value >> 16) & 0xfff;
|
|
DeviceWrite(_offset, data);
|
|
break;
|
|
default:
|
|
Logger.Error?.Print(LogClass.Host1x, $"Unsupported opcode \"{opCode}\".");
|
|
break;
|
|
}
|
|
}
|
|
|
|
private void DeviceWrite(int offset, int data)
|
|
{
|
|
_device?.Write(offset * 4, data);
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
_commandQueue.Dispose();
|
|
_devices.Dispose();
|
|
}
|
|
}
|
|
}
|