using Ryujinx.Graphics.GAL.Multithreading.Commands; using Ryujinx.Graphics.GAL.Multithreading.Commands.Buffer; using Ryujinx.Graphics.GAL.Multithreading.Commands.CounterEvent; using Ryujinx.Graphics.GAL.Multithreading.Commands.ImageArray; using Ryujinx.Graphics.GAL.Multithreading.Commands.Program; using Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer; using Ryujinx.Graphics.GAL.Multithreading.Commands.Sampler; using Ryujinx.Graphics.GAL.Multithreading.Commands.Texture; using Ryujinx.Graphics.GAL.Multithreading.Commands.TextureArray; using Ryujinx.Graphics.GAL.Multithreading.Commands.Window; using System; using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace Ryujinx.Graphics.GAL.Multithreading { static class CommandHelper { private delegate void CommandDelegate(Span memory, ThreadedRenderer threaded, IRenderer renderer); private static readonly int _totalCommands = (int)Enum.GetValues().Max() + 1; private static readonly CommandDelegate[] _lookup = new CommandDelegate[_totalCommands]; [MethodImpl(MethodImplOptions.AggressiveInlining)] private static ref T GetCommand(Span memory) { return ref Unsafe.As(ref MemoryMarshal.GetReference(memory)); } public static int GetMaxCommandSize() { return InitLookup() + 1; // 1 byte reserved for command size. } private static int InitLookup() { int maxCommandSize = 0; void Register(CommandType commandType) where T : unmanaged, IGALCommand, IGALCommand { maxCommandSize = Math.Max(maxCommandSize, Unsafe.SizeOf()); _lookup[(int)commandType] = (memory, threaded, renderer) => T.Run(ref GetCommand(memory), threaded, renderer); } Register(CommandType.Action); Register(CommandType.CreateBufferAccess); Register(CommandType.CreateBufferSparse); Register(CommandType.CreateHostBuffer); Register(CommandType.CreateImageArray); Register(CommandType.CreateProgram); Register(CommandType.CreateSampler); Register(CommandType.CreateSync); Register(CommandType.CreateTexture); Register(CommandType.CreateTextureArray); Register(CommandType.GetCapabilities); Register(CommandType.PreFrame); Register(CommandType.ReportCounter); Register(CommandType.ResetCounter); Register(CommandType.UpdateCounters); Register(CommandType.BufferDispose); Register(CommandType.BufferGetData); Register(CommandType.BufferSetData); Register(CommandType.CounterEventDispose); Register(CommandType.CounterEventFlush); Register(CommandType.ImageArraySetFormats); Register(CommandType.ImageArraySetImages); Register(CommandType.ProgramDispose); Register(CommandType.ProgramGetBinary); Register(CommandType.ProgramCheckLink); Register(CommandType.SamplerDispose); Register(CommandType.TextureCopyTo); Register(CommandType.TextureCopyToScaled); Register(CommandType.TextureCopyToSlice); Register(CommandType.TextureCopyToBuffer); Register(CommandType.TextureCreateView); Register(CommandType.TextureGetData); Register(CommandType.TextureGetDataSlice); Register(CommandType.TextureRelease); Register(CommandType.TextureSetData); Register(CommandType.TextureSetDataSlice); Register(CommandType.TextureSetDataSliceRegion); Register(CommandType.TextureSetStorage); Register(CommandType.TextureArraySetSamplers); Register(CommandType.TextureArraySetTextures); Register(CommandType.WindowPresent); Register(CommandType.Barrier); Register(CommandType.BeginTransformFeedback); Register(CommandType.ClearBuffer); Register(CommandType.ClearRenderTargetColor); Register(CommandType.ClearRenderTargetDepthStencil); Register(CommandType.CommandBufferBarrier); Register(CommandType.CopyBuffer); Register(CommandType.DispatchCompute); Register(CommandType.Draw); Register(CommandType.DrawIndexed); Register(CommandType.DrawIndexedIndirect); Register(CommandType.DrawIndexedIndirectCount); Register(CommandType.DrawIndirect); Register(CommandType.DrawIndirectCount); Register(CommandType.DrawTexture); Register(CommandType.EndHostConditionalRendering); Register(CommandType.EndTransformFeedback); Register(CommandType.SetAlphaTest); Register(CommandType.SetBlendStateAdvanced); Register(CommandType.SetBlendState); Register(CommandType.SetDepthBias); Register(CommandType.SetDepthClamp); Register(CommandType.SetDepthMode); Register(CommandType.SetDepthTest); Register(CommandType.SetFaceCulling); Register(CommandType.SetFrontFace); Register(CommandType.SetStorageBuffers); Register(CommandType.SetTransformFeedbackBuffers); Register(CommandType.SetUniformBuffers); Register(CommandType.SetImage); Register(CommandType.SetImageArray); Register(CommandType.SetIndexBuffer); Register(CommandType.SetLineParameters); Register(CommandType.SetLogicOpState); Register(CommandType.SetMultisampleState); Register(CommandType.SetPatchParameters); Register(CommandType.SetPointParameters); Register(CommandType.SetPolygonMode); Register(CommandType.SetPrimitiveRestart); Register(CommandType.SetPrimitiveTopology); Register(CommandType.SetProgram); Register(CommandType.SetRasterizerDiscard); Register(CommandType.SetRenderTargetColorMasks); Register(CommandType.SetRenderTargets); Register(CommandType.SetScissor); Register(CommandType.SetStencilTest); Register(CommandType.SetTextureAndSampler); Register(CommandType.SetTextureArray); Register(CommandType.SetUserClipDistance); Register(CommandType.SetVertexAttribs); Register(CommandType.SetVertexBuffers); Register(CommandType.SetViewports); Register(CommandType.TextureBarrier); Register(CommandType.TextureBarrierTiled); Register(CommandType.TryHostConditionalRendering); Register(CommandType.TryHostConditionalRenderingFlush); return maxCommandSize; } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void RunCommand(Span memory, ThreadedRenderer threaded, IRenderer renderer) { _lookup[memory[^1]](memory, threaded, renderer); } } }