| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190 |
- using Ryujinx.Graphics.Gpu.State;
- using System;
- using System.Runtime.CompilerServices;
- namespace Ryujinx.Graphics.Gpu.Engine.GPFifo
- {
- /// <summary>
- /// Represents a GPU General Purpose FIFO command processor.
- /// </summary>
- class GPFifoProcessor
- {
- private const int MacrosCount = 0x80;
- private const int MacroIndexMask = MacrosCount - 1;
- private readonly GpuContext _context;
- /// <summary>
- /// Internal GPFIFO state.
- /// </summary>
- private struct DmaState
- {
- public int Method;
- public int SubChannel;
- public int MethodCount;
- public bool NonIncrementing;
- public bool IncrementOnce;
- }
- private DmaState _state;
- private readonly GpuState[] _subChannels;
- private readonly GPFifoClass _fifoClass;
- /// <summary>
- /// Creates a new instance of the GPU General Purpose FIFO command processor.
- /// </summary>
- /// <param name="context">GPU context</param>
- public GPFifoProcessor(GpuContext context)
- {
- _context = context;
- _fifoClass = new GPFifoClass(context, this);
- _subChannels = new GpuState[8];
- for (int index = 0; index < _subChannels.Length; index++)
- {
- _subChannels[index] = new GpuState();
- _context.Methods.RegisterCallbacks(_subChannels[index]);
- }
- }
- /// <summary>
- /// Processes a command buffer.
- /// </summary>
- /// <param name="commandBuffer">Command buffer</param>
- public void Process(ReadOnlySpan<int> commandBuffer)
- {
- for (int index = 0; index < commandBuffer.Length; index++)
- {
- int command = commandBuffer[index];
- if (_state.MethodCount != 0)
- {
- Send(new MethodParams(_state.Method, command, _state.SubChannel, _state.MethodCount));
- if (!_state.NonIncrementing)
- {
- _state.Method++;
- }
- if (_state.IncrementOnce)
- {
- _state.NonIncrementing = true;
- }
- _state.MethodCount--;
- }
- else
- {
- CompressedMethod meth = Unsafe.As<int, CompressedMethod>(ref command);
- if (TryFastUniformBufferUpdate(meth, commandBuffer, index))
- {
- index += meth.MethodCount;
- continue;
- }
- switch (meth.SecOp)
- {
- case SecOp.IncMethod:
- case SecOp.NonIncMethod:
- case SecOp.OneInc:
- _state.Method = meth.MethodAddress;
- _state.SubChannel = meth.MethodSubchannel;
- _state.MethodCount = meth.MethodCount;
- _state.IncrementOnce = meth.SecOp == SecOp.OneInc;
- _state.NonIncrementing = meth.SecOp == SecOp.NonIncMethod;
- break;
- case SecOp.ImmdDataMethod:
- Send(new MethodParams(meth.MethodAddress, meth.ImmdData, meth.MethodSubchannel, 1));
- break;
- }
- }
- }
- }
- /// <summary>
- /// Tries to perform a fast constant buffer data update.
- /// If successful, all data will be copied at once, and <see cref="CompressedMethod.MethodCount"/> + 1
- /// command buffer entries will be consumed.
- /// </summary>
- /// <param name="meth">Compressed method to be checked</param>
- /// <param name="commandBuffer">Command buffer where <paramref name="meth"/> is contained</param>
- /// <param name="offset">Offset at <paramref name="commandBuffer"/> where <paramref name="meth"/> is located</param>
- /// <returns>True if the fast copy was successful, false otherwise</returns>
- private bool TryFastUniformBufferUpdate(CompressedMethod meth, ReadOnlySpan<int> commandBuffer, int offset)
- {
- int availableCount = commandBuffer.Length - offset;
- if (meth.MethodCount < availableCount &&
- meth.SecOp == SecOp.NonIncMethod &&
- meth.MethodAddress == (int)MethodOffset.UniformBufferUpdateData)
- {
- GpuState state = _subChannels[meth.MethodSubchannel];
- _context.Methods.UniformBufferUpdate(state, commandBuffer.Slice(offset + 1, meth.MethodCount));
- return true;
- }
- return false;
- }
- /// <summary>
- /// Sends a uncompressed method for processing by the graphics pipeline.
- /// </summary>
- /// <param name="meth">Method to be processed</param>
- private void Send(MethodParams meth)
- {
- if ((MethodOffset)meth.Method == MethodOffset.BindChannel)
- {
- _subChannels[meth.SubChannel] = new GpuState();
- _context.Methods.RegisterCallbacks(_subChannels[meth.SubChannel]);
- }
- else if (meth.Method < 0x60)
- {
- // TODO: check if macros are shared between subchannels or not. For now let's assume they are.
- _fifoClass.Write(meth.Method * 4, meth.Argument);
- }
- else if (meth.Method < 0xe00)
- {
- _subChannels[meth.SubChannel].CallMethod(meth);
- }
- else
- {
- int macroIndex = (meth.Method >> 1) & MacroIndexMask;
- if ((meth.Method & 1) != 0)
- {
- _fifoClass.MmePushArgument(macroIndex, meth.Argument);
- }
- else
- {
- _fifoClass.MmeStart(macroIndex, meth.Argument);
- }
- if (meth.IsLastCall)
- {
- _fifoClass.CallMme(macroIndex, _subChannels[meth.SubChannel]);
- _context.Methods.PerformDeferredDraws();
- }
- }
- }
- /// <summary>
- /// Sets the shadow ram control value of all sub-channels.
- /// </summary>
- /// <param name="control">New shadow ram control value</param>
- public void SetShadowRamControl(ShadowRamControl control)
- {
- for (int i = 0; i < _subChannels.Length; i++)
- {
- _subChannels[i].ShadowRamControl = control;
- }
- }
- }
- }
|