 f4f496cb48
			
		
	
	
		f4f496cb48
		
			
		
	
	
	
	
		
			
			* 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
		
			
				
	
	
		
			174 lines
		
	
	
	
		
			4.7 KiB
		
	
	
	
		
			C#
		
	
	
	
	
	
			
		
		
	
	
			174 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();
 | |
|         }
 | |
|     }
 | |
| }
 |