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.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.Window; using System; using System.Collections.Generic; using System.Linq; using System.Reflection; 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 int _totalCommands = (int)Enum.GetValues().Max() + 1; private static 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() { Assembly assembly = typeof(CommandHelper).Assembly; IEnumerable commands = assembly.GetTypes().Where(type => typeof(IGALCommand).IsAssignableFrom(type) && type.IsValueType); int maxSize = commands.Max(command => { MethodInfo method = typeof(Unsafe).GetMethod(nameof(Unsafe.SizeOf)); MethodInfo generic = method.MakeGenericMethod(command); int size = (int)generic.Invoke(null, null); return size; }); InitLookup(); return maxSize + 1; // 1 byte reserved for command size. } private static void InitLookup() { _lookup[(int)CommandType.Action] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => ActionCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.CreateBuffer] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => CreateBufferCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.CreateProgram] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => CreateProgramCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.CreateSampler] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => CreateSamplerCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.CreateSync] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => CreateSyncCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.CreateTexture] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => CreateTextureCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.GetCapabilities] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => GetCapabilitiesCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.PreFrame] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => PreFrameCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.ReportCounter] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => ReportCounterCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.ResetCounter] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => ResetCounterCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.UpdateCounters] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => UpdateCountersCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.BufferDispose] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => BufferDisposeCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.BufferGetData] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => BufferGetDataCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.BufferSetData] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => BufferSetDataCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.CounterEventDispose] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => CounterEventDisposeCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.CounterEventFlush] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => CounterEventFlushCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.ProgramDispose] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => ProgramDisposeCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.ProgramGetBinary] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => ProgramGetBinaryCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.ProgramCheckLink] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => ProgramCheckLinkCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SamplerDispose] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SamplerDisposeCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.TextureCopyTo] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => TextureCopyToCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.TextureCopyToScaled] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => TextureCopyToScaledCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.TextureCopyToSlice] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => TextureCopyToSliceCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.TextureCreateView] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => TextureCreateViewCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.TextureGetData] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => TextureGetDataCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.TextureGetDataSlice] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => TextureGetDataSliceCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.TextureRelease] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => TextureReleaseCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.TextureSetData] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => TextureSetDataCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.TextureSetDataSlice] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => TextureSetDataSliceCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.TextureSetStorage] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => TextureSetStorageCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.WindowPresent] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => WindowPresentCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.Barrier] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => BarrierCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.BeginTransformFeedback] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => BeginTransformFeedbackCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.ClearBuffer] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => ClearBufferCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.ClearRenderTargetColor] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => ClearRenderTargetColorCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.ClearRenderTargetDepthStencil] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => ClearRenderTargetDepthStencilCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.CommandBufferBarrier] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => CommandBufferBarrierCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.CopyBuffer] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => CopyBufferCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.DispatchCompute] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => DispatchComputeCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.Draw] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => DrawCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.DrawIndexed] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => DrawIndexedCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.DrawTexture] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => DrawTextureCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.EndHostConditionalRendering] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => EndHostConditionalRenderingCommand.Run(renderer); _lookup[(int)CommandType.EndTransformFeedback] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => EndTransformFeedbackCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.MultiDrawIndirectCount] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => MultiDrawIndirectCountCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.MultiDrawIndexedIndirectCount] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => MultiDrawIndexedIndirectCountCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetAlphaTest] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetAlphaTestCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetBlendState] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetBlendStateCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetDepthBias] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetDepthBiasCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetDepthClamp] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetDepthClampCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetDepthMode] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetDepthModeCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetDepthTest] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetDepthTestCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetFaceCulling] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetFaceCullingCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetFrontFace] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetFrontFaceCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetStorageBuffers] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetStorageBuffersCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetTransformFeedbackBuffers] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetTransformFeedbackBuffersCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetUniformBuffers] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetUniformBuffersCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetImage] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetImageCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetIndexBuffer] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetIndexBufferCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetLineParameters] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetLineParametersCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetLogicOpState] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetLogicOpStateCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetPatchParameters] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetPatchParametersCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetPointParameters] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetPointParametersCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetPolygonMode] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetPolygonModeCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetPrimitiveRestart] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetPrimitiveRestartCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetPrimitiveTopology] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetPrimitiveTopologyCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetProgram] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetProgramCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetRasterizerDiscard] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetRasterizerDiscardCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetRenderTargetColorMasks] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetRenderTargetColorMasksCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetRenderTargetScale] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetRenderTargetScaleCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetRenderTargets] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetRenderTargetsCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetSampler] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetSamplerCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetScissor] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetScissorCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetStencilTest] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetStencilTestCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetTexture] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetTextureCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetUserClipDistance] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetUserClipDistanceCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetVertexAttribs] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetVertexAttribsCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetVertexBuffers] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetVertexBuffersCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.SetViewports] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => SetViewportsCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.TextureBarrier] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => TextureBarrierCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.TextureBarrierTiled] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => TextureBarrierTiledCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.TryHostConditionalRendering] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => TryHostConditionalRenderingCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.TryHostConditionalRenderingFlush] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => TryHostConditionalRenderingFlushCommand.Run(ref GetCommand(memory), threaded, renderer); _lookup[(int)CommandType.UpdateRenderScale] = (Span memory, ThreadedRenderer threaded, IRenderer renderer) => UpdateRenderScaleCommand.Run(ref GetCommand(memory), threaded, renderer); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void RunCommand(Span memory, ThreadedRenderer threaded, IRenderer renderer) { _lookup[memory[memory.Length - 1]](memory, threaded, renderer); } } }