From 7fea26e97e74e7ec0a5fa27921aa40c31b2c1dd9 Mon Sep 17 00:00:00 2001
From: gdkchan <gab.dark.100@gmail.com>
Date: Sat, 21 Jan 2023 21:07:43 -0300
Subject: [PATCH] Remove use of reflection on GAL multithreading (#4287)

* Introduce new IGALCommand<T> interface and use it

* Remove use of reflection on GAL multithreading

* Unmanaged constraint
---
 .../Multithreading/CommandHelper.cs           | 292 ++++++------------
 .../Multithreading/Commands/BarrierCommand.cs |   2 +-
 .../Commands/BeginTransformFeedbackCommand.cs |   2 +-
 .../Commands/Buffer/BufferDisposeCommand.cs   |   2 +-
 .../Commands/Buffer/BufferGetDataCommand.cs   |   2 +-
 .../Commands/Buffer/BufferSetDataCommand.cs   |   2 +-
 .../Commands/ClearBufferCommand.cs            |   2 +-
 .../Commands/ClearRenderTargetColorCommand.cs |   2 +-
 .../ClearRenderTargetDepthStencilCommand.cs   |   2 +-
 .../Commands/CommandBufferBarrierCommand.cs   |   2 +-
 .../Commands/CopyBufferCommand.cs             |   2 +-
 .../CounterEventDisposeCommand.cs             |   2 +-
 .../CounterEvent/CounterEventFlushCommand.cs  |   2 +-
 .../Commands/DispatchComputeCommand.cs        |   2 +-
 .../Multithreading/Commands/DrawCommand.cs    |   2 +-
 .../Commands/DrawIndexedCommand.cs            |   2 +-
 .../Commands/DrawIndexedIndirectCommand.cs    |   2 +-
 .../DrawIndexedIndirectCountCommand.cs        |   2 +-
 .../Commands/DrawIndirectCommand.cs           |   2 +-
 .../Commands/DrawIndirectCountCommand.cs      |   2 +-
 .../Commands/DrawTextureCommand.cs            |   2 +-
 .../EndHostConditionalRenderingCommand.cs     |   4 +-
 .../Commands/EndTransformFeedbackCommand.cs   |   2 +-
 .../Multithreading/Commands/IGALCommand.cs    |   5 +
 .../Program/ProgramCheckLinkCommand.cs        |   2 +-
 .../Commands/Program/ProgramDisposeCommand.cs |   2 +-
 .../Program/ProgramGetBinaryCommand.cs        |   2 +-
 .../Commands/Renderer/ActionCommand.cs        |   2 +-
 .../Commands/Renderer/CreateBufferCommand.cs  |   2 +-
 .../Commands/Renderer/CreateProgramCommand.cs |   2 +-
 .../Commands/Renderer/CreateSamplerCommand.cs |   2 +-
 .../Commands/Renderer/CreateSyncCommand.cs    |   2 +-
 .../Commands/Renderer/CreateTextureCommand.cs |   2 +-
 .../Renderer/GetCapabilitiesCommand.cs        |   2 +-
 .../Commands/Renderer/PreFrameCommand.cs      |   2 +-
 .../Commands/Renderer/ReportCounterCommand.cs |   2 +-
 .../Commands/Renderer/ResetCounterCommand.cs  |   2 +-
 .../Renderer/UpdateCountersCommand.cs         |   2 +-
 .../Commands/Sampler/SamplerDisposeCommand.cs |   2 +-
 .../Commands/SetAlphaTestCommand.cs           |   2 +-
 .../Commands/SetBlendStateCommand.cs          |   2 +-
 .../Commands/SetDepthBiasCommand.cs           |   2 +-
 .../Commands/SetDepthClampCommand.cs          |   2 +-
 .../Commands/SetDepthModeCommand.cs           |   2 +-
 .../Commands/SetDepthTestCommand.cs           |   2 +-
 .../Commands/SetFaceCullingCommand.cs         |   2 +-
 .../Commands/SetFrontFaceCommand.cs           |   2 +-
 .../Commands/SetImageCommand.cs               |   2 +-
 .../Commands/SetIndexBufferCommand.cs         |   2 +-
 .../Commands/SetLineParametersCommand.cs      |   2 +-
 .../Commands/SetLogicOpStateCommand.cs        |   2 +-
 .../Commands/SetMultisampleStateCommand.cs    |   2 +-
 .../Commands/SetPatchParametersCommand.cs     |   2 +-
 .../Commands/SetPointParametersCommand.cs     |   2 +-
 .../Commands/SetPolygonModeCommand.cs         |   2 +-
 .../Commands/SetPrimitiveRestartCommand.cs    |   2 +-
 .../Commands/SetPrimitiveTopologyCommand.cs   |   2 +-
 .../Commands/SetProgramCommand.cs             |   2 +-
 .../Commands/SetRasterizerDiscardCommand.cs   |   2 +-
 .../SetRenderTargetColorMasksCommand.cs       |   2 +-
 .../Commands/SetRenderTargetScaleCommand.cs   |   2 +-
 .../Commands/SetRenderTargetsCommand.cs       |   2 +-
 .../Commands/SetScissorsCommand.cs            |   2 +-
 .../Commands/SetStencilTestCommand.cs         |   2 +-
 .../Commands/SetStorageBuffersCommand.cs      |   2 +-
 .../Commands/SetTextureAndSamplerCommand.cs   |   2 +-
 .../SetTransformFeedbackBuffersCommand.cs     |   2 +-
 .../Commands/SetUniformBuffersCommand.cs      |   2 +-
 .../Commands/SetUserClipDistanceCommand.cs    |   2 +-
 .../Commands/SetVertexAttribsCommand.cs       |   2 +-
 .../Commands/SetVertexBuffersCommand.cs       |   2 +-
 .../Commands/SetViewportsCommand.cs           |   2 +-
 .../Commands/Texture/TextureCopyToCommand.cs  |   2 +-
 .../Texture/TextureCopyToScaledCommand.cs     |   2 +-
 .../Texture/TextureCopyToSliceCommand.cs      |   2 +-
 .../Texture/TextureCreateViewCommand.cs       |   2 +-
 .../Commands/Texture/TextureGetDataCommand.cs |   2 +-
 .../Texture/TextureGetDataSliceCommand.cs     |   2 +-
 .../Commands/Texture/TextureReleaseCommand.cs |   2 +-
 .../Commands/Texture/TextureSetDataCommand.cs |   2 +-
 .../Texture/TextureSetDataSliceCommand.cs     |   2 +-
 .../TextureSetDataSliceRegionCommand.cs       |   2 +-
 .../Texture/TextureSetStorageCommand.cs       |   2 +-
 .../Commands/TextureBarrierCommand.cs         |   2 +-
 .../Commands/TextureBarrierTiledCommand.cs    |   2 +-
 .../TryHostConditionalRenderingCommand.cs     |   2 +-
 ...TryHostConditionalRenderingFlushCommand.cs |   2 +-
 .../Commands/UpdateRenderScaleCommand.cs      |   2 +-
 .../Commands/Window/WindowPresentCommand.cs   |   2 +-
 89 files changed, 192 insertions(+), 281 deletions(-)

diff --git a/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs b/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs
index 49769329..48873491 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/CommandHelper.cs
@@ -7,9 +7,7 @@ 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;
 
@@ -30,207 +28,115 @@ namespace Ryujinx.Graphics.GAL.Multithreading
 
         public static int GetMaxCommandSize()
         {
-            Assembly assembly = typeof(CommandHelper).Assembly;
-
-            IEnumerable<Type> 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.
+            return InitLookup() + 1; // 1 byte reserved for command size.
         }
 
-        private static void InitLookup()
+        private static int InitLookup()
         {
-            _lookup[(int)CommandType.Action] = (memory, threaded, renderer) =>
-                ActionCommand.Run(ref GetCommand<ActionCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.CreateBuffer] = (memory, threaded, renderer) =>
-                CreateBufferCommand.Run(ref GetCommand<CreateBufferCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.CreateProgram] = (memory, threaded, renderer) =>
-                CreateProgramCommand.Run(ref GetCommand<CreateProgramCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.CreateSampler] = (memory, threaded, renderer) =>
-                CreateSamplerCommand.Run(ref GetCommand<CreateSamplerCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.CreateSync] = (memory, threaded, renderer) =>
-                CreateSyncCommand.Run(ref GetCommand<CreateSyncCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.CreateTexture] = (memory, threaded, renderer) =>
-                CreateTextureCommand.Run(ref GetCommand<CreateTextureCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.GetCapabilities] = (memory, threaded, renderer) =>
-                GetCapabilitiesCommand.Run(ref GetCommand<GetCapabilitiesCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.PreFrame] = (memory, threaded, renderer) =>
-                PreFrameCommand.Run(ref GetCommand<PreFrameCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.ReportCounter] = (memory, threaded, renderer) =>
-                ReportCounterCommand.Run(ref GetCommand<ReportCounterCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.ResetCounter] = (memory, threaded, renderer) =>
-                ResetCounterCommand.Run(ref GetCommand<ResetCounterCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.UpdateCounters] = (memory, threaded, renderer) =>
-                UpdateCountersCommand.Run(ref GetCommand<UpdateCountersCommand>(memory), threaded, renderer);
+            int maxCommandSize = 0;
 
-            _lookup[(int)CommandType.BufferDispose] = (memory, threaded, renderer) =>
-                BufferDisposeCommand.Run(ref GetCommand<BufferDisposeCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.BufferGetData] = (memory, threaded, renderer) =>
-                BufferGetDataCommand.Run(ref GetCommand<BufferGetDataCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.BufferSetData] = (memory, threaded, renderer) =>
-                BufferSetDataCommand.Run(ref GetCommand<BufferSetDataCommand>(memory), threaded, renderer);
+            void Register<T>(CommandType commandType) where T : unmanaged, IGALCommand, IGALCommand<T>
+            {
+                maxCommandSize = Math.Max(maxCommandSize, Unsafe.SizeOf<T>());
+                _lookup[(int)commandType] = (memory, threaded, renderer) => T.Run(ref GetCommand<T>(memory), threaded, renderer);
+            }
 
-            _lookup[(int)CommandType.CounterEventDispose] = (memory, threaded, renderer) =>
-                CounterEventDisposeCommand.Run(ref GetCommand<CounterEventDisposeCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.CounterEventFlush] = (memory, threaded, renderer) =>
-                CounterEventFlushCommand.Run(ref GetCommand<CounterEventFlushCommand>(memory), threaded, renderer);
+            Register<ActionCommand>(CommandType.Action);
+            Register<CreateBufferCommand>(CommandType.CreateBuffer);
+            Register<CreateProgramCommand>(CommandType.CreateProgram);
+            Register<CreateSamplerCommand>(CommandType.CreateSampler);
+            Register<CreateSyncCommand>(CommandType.CreateSync);
+            Register<CreateTextureCommand>(CommandType.CreateTexture);
+            Register<GetCapabilitiesCommand>(CommandType.GetCapabilities);
+            Register<PreFrameCommand>(CommandType.PreFrame);
+            Register<ReportCounterCommand>(CommandType.ReportCounter);
+            Register<ResetCounterCommand>(CommandType.ResetCounter);
+            Register<UpdateCountersCommand>(CommandType.UpdateCounters);
 
-            _lookup[(int)CommandType.ProgramDispose] = (memory, threaded, renderer) =>
-                ProgramDisposeCommand.Run(ref GetCommand<ProgramDisposeCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.ProgramGetBinary] = (memory, threaded, renderer) =>
-                ProgramGetBinaryCommand.Run(ref GetCommand<ProgramGetBinaryCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.ProgramCheckLink] = (memory, threaded, renderer) =>
-                ProgramCheckLinkCommand.Run(ref GetCommand<ProgramCheckLinkCommand>(memory), threaded, renderer);
+            Register<BufferDisposeCommand>(CommandType.BufferDispose);
+            Register<BufferGetDataCommand>(CommandType.BufferGetData);
+            Register<BufferSetDataCommand>(CommandType.BufferSetData);
 
-            _lookup[(int)CommandType.SamplerDispose] = (memory, threaded, renderer) =>
-                SamplerDisposeCommand.Run(ref GetCommand<SamplerDisposeCommand>(memory), threaded, renderer);
+            Register<CounterEventDisposeCommand>(CommandType.CounterEventDispose);
+            Register<CounterEventFlushCommand>(CommandType.CounterEventFlush);
 
-            _lookup[(int)CommandType.TextureCopyTo] = (memory, threaded, renderer) =>
-                TextureCopyToCommand.Run(ref GetCommand<TextureCopyToCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.TextureCopyToScaled] = (memory, threaded, renderer) =>
-                TextureCopyToScaledCommand.Run(ref GetCommand<TextureCopyToScaledCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.TextureCopyToSlice] = (memory, threaded, renderer) =>
-                TextureCopyToSliceCommand.Run(ref GetCommand<TextureCopyToSliceCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.TextureCreateView] = (memory, threaded, renderer) =>
-                TextureCreateViewCommand.Run(ref GetCommand<TextureCreateViewCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.TextureGetData] = (memory, threaded, renderer) =>
-                TextureGetDataCommand.Run(ref GetCommand<TextureGetDataCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.TextureGetDataSlice] = (memory, threaded, renderer) =>
-                TextureGetDataSliceCommand.Run(ref GetCommand<TextureGetDataSliceCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.TextureRelease] = (memory, threaded, renderer) =>
-                TextureReleaseCommand.Run(ref GetCommand<TextureReleaseCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.TextureSetData] = (memory, threaded, renderer) =>
-                TextureSetDataCommand.Run(ref GetCommand<TextureSetDataCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.TextureSetDataSlice] = (memory, threaded, renderer) =>
-                TextureSetDataSliceCommand.Run(ref GetCommand<TextureSetDataSliceCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.TextureSetDataSliceRegion] = (memory, threaded, renderer) =>
-                TextureSetDataSliceRegionCommand.Run(ref GetCommand<TextureSetDataSliceRegionCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.TextureSetStorage] = (memory, threaded, renderer) =>
-                TextureSetStorageCommand.Run(ref GetCommand<TextureSetStorageCommand>(memory), threaded, renderer);
+            Register<ProgramDisposeCommand>(CommandType.ProgramDispose);
+            Register<ProgramGetBinaryCommand>(CommandType.ProgramGetBinary);
+            Register<ProgramCheckLinkCommand>(CommandType.ProgramCheckLink);
 
-            _lookup[(int)CommandType.WindowPresent] = (memory, threaded, renderer) =>
-                WindowPresentCommand.Run(ref GetCommand<WindowPresentCommand>(memory), threaded, renderer);
+            Register<SamplerDisposeCommand>(CommandType.SamplerDispose);
 
-            _lookup[(int)CommandType.Barrier] = (memory, threaded, renderer) =>
-                BarrierCommand.Run(ref GetCommand<BarrierCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.BeginTransformFeedback] = (memory, threaded, renderer) =>
-                BeginTransformFeedbackCommand.Run(ref GetCommand<BeginTransformFeedbackCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.ClearBuffer] = (memory, threaded, renderer) =>
-                ClearBufferCommand.Run(ref GetCommand<ClearBufferCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.ClearRenderTargetColor] = (memory, threaded, renderer) =>
-                ClearRenderTargetColorCommand.Run(ref GetCommand<ClearRenderTargetColorCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.ClearRenderTargetDepthStencil] = (memory, threaded, renderer) =>
-                ClearRenderTargetDepthStencilCommand.Run(ref GetCommand<ClearRenderTargetDepthStencilCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.CommandBufferBarrier] = (memory, threaded, renderer) =>
-                CommandBufferBarrierCommand.Run(ref GetCommand<CommandBufferBarrierCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.CopyBuffer] = (memory, threaded, renderer) =>
-                CopyBufferCommand.Run(ref GetCommand<CopyBufferCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.DispatchCompute] = (memory, threaded, renderer) =>
-                DispatchComputeCommand.Run(ref GetCommand<DispatchComputeCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.Draw] = (memory, threaded, renderer) =>
-                DrawCommand.Run(ref GetCommand<DrawCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.DrawIndexed] = (memory, threaded, renderer) =>
-                DrawIndexedCommand.Run(ref GetCommand<DrawIndexedCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.DrawIndexedIndirect] = (memory, threaded, renderer) =>
-                DrawIndexedIndirectCommand.Run(ref GetCommand<DrawIndexedIndirectCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.DrawIndexedIndirectCount] = (memory, threaded, renderer) =>
-                DrawIndexedIndirectCountCommand.Run(ref GetCommand<DrawIndexedIndirectCountCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.DrawIndirect] = (memory, threaded, renderer) =>
-                DrawIndirectCommand.Run(ref GetCommand<DrawIndirectCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.DrawIndirectCount] = (memory, threaded, renderer) =>
-                DrawIndirectCountCommand.Run(ref GetCommand<DrawIndirectCountCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.DrawTexture] = (memory, threaded, renderer) =>
-                DrawTextureCommand.Run(ref GetCommand<DrawTextureCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.EndHostConditionalRendering] = (memory, threaded, renderer) =>
-                EndHostConditionalRenderingCommand.Run(renderer);
-            _lookup[(int)CommandType.EndTransformFeedback] = (memory, threaded, renderer) =>
-                EndTransformFeedbackCommand.Run(ref GetCommand<EndTransformFeedbackCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetAlphaTest] = (memory, threaded, renderer) =>
-                SetAlphaTestCommand.Run(ref GetCommand<SetAlphaTestCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetBlendState] = (memory, threaded, renderer) =>
-                SetBlendStateCommand.Run(ref GetCommand<SetBlendStateCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetDepthBias] = (memory, threaded, renderer) =>
-                SetDepthBiasCommand.Run(ref GetCommand<SetDepthBiasCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetDepthClamp] = (memory, threaded, renderer) =>
-                SetDepthClampCommand.Run(ref GetCommand<SetDepthClampCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetDepthMode] = (memory, threaded, renderer) =>
-                SetDepthModeCommand.Run(ref GetCommand<SetDepthModeCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetDepthTest] = (memory, threaded, renderer) =>
-                SetDepthTestCommand.Run(ref GetCommand<SetDepthTestCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetFaceCulling] = (memory, threaded, renderer) =>
-                SetFaceCullingCommand.Run(ref GetCommand<SetFaceCullingCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetFrontFace] = (memory, threaded, renderer) =>
-                SetFrontFaceCommand.Run(ref GetCommand<SetFrontFaceCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetStorageBuffers] = (memory, threaded, renderer) =>
-                SetStorageBuffersCommand.Run(ref GetCommand<SetStorageBuffersCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetTransformFeedbackBuffers] = (memory, threaded, renderer) =>
-                SetTransformFeedbackBuffersCommand.Run(ref GetCommand<SetTransformFeedbackBuffersCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetUniformBuffers] = (memory, threaded, renderer) =>
-                SetUniformBuffersCommand.Run(ref GetCommand<SetUniformBuffersCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetImage] = (memory, threaded, renderer) =>
-                SetImageCommand.Run(ref GetCommand<SetImageCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetIndexBuffer] = (memory, threaded, renderer) =>
-                SetIndexBufferCommand.Run(ref GetCommand<SetIndexBufferCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetLineParameters] = (memory, threaded, renderer) =>
-                SetLineParametersCommand.Run(ref GetCommand<SetLineParametersCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetLogicOpState] = (memory, threaded, renderer) =>
-                SetLogicOpStateCommand.Run(ref GetCommand<SetLogicOpStateCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetMultisampleState] = (memory, threaded, renderer) =>
-                SetMultisampleStateCommand.Run(ref GetCommand<SetMultisampleStateCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetPatchParameters] = (memory, threaded, renderer) =>
-                SetPatchParametersCommand.Run(ref GetCommand<SetPatchParametersCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetPointParameters] = (memory, threaded, renderer) =>
-                SetPointParametersCommand.Run(ref GetCommand<SetPointParametersCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetPolygonMode] = (memory, threaded, renderer) =>
-                SetPolygonModeCommand.Run(ref GetCommand<SetPolygonModeCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetPrimitiveRestart] = (memory, threaded, renderer) =>
-                SetPrimitiveRestartCommand.Run(ref GetCommand<SetPrimitiveRestartCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetPrimitiveTopology] = (memory, threaded, renderer) =>
-                SetPrimitiveTopologyCommand.Run(ref GetCommand<SetPrimitiveTopologyCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetProgram] = (memory, threaded, renderer) =>
-                SetProgramCommand.Run(ref GetCommand<SetProgramCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetRasterizerDiscard] = (memory, threaded, renderer) =>
-                SetRasterizerDiscardCommand.Run(ref GetCommand<SetRasterizerDiscardCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetRenderTargetColorMasks] = (memory, threaded, renderer) =>
-                SetRenderTargetColorMasksCommand.Run(ref GetCommand<SetRenderTargetColorMasksCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetRenderTargetScale] = (memory, threaded, renderer) =>
-                SetRenderTargetScaleCommand.Run(ref GetCommand<SetRenderTargetScaleCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetRenderTargets] = (memory, threaded, renderer) =>
-                SetRenderTargetsCommand.Run(ref GetCommand<SetRenderTargetsCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetScissor] = (memory, threaded, renderer) =>
-                SetScissorsCommand.Run(ref GetCommand<SetScissorsCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetStencilTest] = (memory, threaded, renderer) =>
-                SetStencilTestCommand.Run(ref GetCommand<SetStencilTestCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetTextureAndSampler] = (memory, threaded, renderer) =>
-                SetTextureAndSamplerCommand.Run(ref GetCommand<SetTextureAndSamplerCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetUserClipDistance] = (memory, threaded, renderer) =>
-                SetUserClipDistanceCommand.Run(ref GetCommand<SetUserClipDistanceCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetVertexAttribs] = (memory, threaded, renderer) =>
-                SetVertexAttribsCommand.Run(ref GetCommand<SetVertexAttribsCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetVertexBuffers] = (memory, threaded, renderer) =>
-                SetVertexBuffersCommand.Run(ref GetCommand<SetVertexBuffersCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.SetViewports] = (memory, threaded, renderer) =>
-                SetViewportsCommand.Run(ref GetCommand<SetViewportsCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.TextureBarrier] = (memory, threaded, renderer) =>
-                TextureBarrierCommand.Run(ref GetCommand<TextureBarrierCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.TextureBarrierTiled] = (memory, threaded, renderer) =>
-                TextureBarrierTiledCommand.Run(ref GetCommand<TextureBarrierTiledCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.TryHostConditionalRendering] = (memory, threaded, renderer) =>
-                TryHostConditionalRenderingCommand.Run(ref GetCommand<TryHostConditionalRenderingCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.TryHostConditionalRenderingFlush] = (memory, threaded, renderer) =>
-                TryHostConditionalRenderingFlushCommand.Run(ref GetCommand<TryHostConditionalRenderingFlushCommand>(memory), threaded, renderer);
-            _lookup[(int)CommandType.UpdateRenderScale] = (memory, threaded, renderer) =>
-                UpdateRenderScaleCommand.Run(ref GetCommand<UpdateRenderScaleCommand>(memory), threaded, renderer);
+            Register<TextureCopyToCommand>(CommandType.TextureCopyTo);
+            Register<TextureCopyToScaledCommand>(CommandType.TextureCopyToScaled);
+            Register<TextureCopyToSliceCommand>(CommandType.TextureCopyToSlice);
+            Register<TextureCreateViewCommand>(CommandType.TextureCreateView);
+            Register<TextureGetDataCommand>(CommandType.TextureGetData);
+            Register<TextureGetDataSliceCommand>(CommandType.TextureGetDataSlice);
+            Register<TextureReleaseCommand>(CommandType.TextureRelease);
+            Register<TextureSetDataCommand>(CommandType.TextureSetData);
+            Register<TextureSetDataSliceCommand>(CommandType.TextureSetDataSlice);
+            Register<TextureSetDataSliceRegionCommand>(CommandType.TextureSetDataSliceRegion);
+            Register<TextureSetStorageCommand>(CommandType.TextureSetStorage);
+
+            Register<WindowPresentCommand>(CommandType.WindowPresent);
+
+            Register<BarrierCommand>(CommandType.Barrier);
+            Register<BeginTransformFeedbackCommand>(CommandType.BeginTransformFeedback);
+            Register<ClearBufferCommand>(CommandType.ClearBuffer);
+            Register<ClearRenderTargetColorCommand>(CommandType.ClearRenderTargetColor);
+            Register<ClearRenderTargetDepthStencilCommand>(CommandType.ClearRenderTargetDepthStencil);
+            Register<CommandBufferBarrierCommand>(CommandType.CommandBufferBarrier);
+            Register<CopyBufferCommand>(CommandType.CopyBuffer);
+            Register<DispatchComputeCommand>(CommandType.DispatchCompute);
+            Register<DrawCommand>(CommandType.Draw);
+            Register<DrawIndexedCommand>(CommandType.DrawIndexed);
+            Register<DrawIndexedIndirectCommand>(CommandType.DrawIndexedIndirect);
+            Register<DrawIndexedIndirectCountCommand>(CommandType.DrawIndexedIndirectCount);
+            Register<DrawIndirectCommand>(CommandType.DrawIndirect);
+            Register<DrawIndirectCountCommand>(CommandType.DrawIndirectCount);
+            Register<DrawTextureCommand>(CommandType.DrawTexture);
+            Register<EndHostConditionalRenderingCommand>(CommandType.EndHostConditionalRendering);
+            Register<EndTransformFeedbackCommand>(CommandType.EndTransformFeedback);
+            Register<SetAlphaTestCommand>(CommandType.SetAlphaTest);
+            Register<SetBlendStateCommand>(CommandType.SetBlendState);
+            Register<SetDepthBiasCommand>(CommandType.SetDepthBias);
+            Register<SetDepthClampCommand>(CommandType.SetDepthClamp);
+            Register<SetDepthModeCommand>(CommandType.SetDepthMode);
+            Register<SetDepthTestCommand>(CommandType.SetDepthTest);
+            Register<SetFaceCullingCommand>(CommandType.SetFaceCulling);
+            Register<SetFrontFaceCommand>(CommandType.SetFrontFace);
+            Register<SetStorageBuffersCommand>(CommandType.SetStorageBuffers);
+            Register<SetTransformFeedbackBuffersCommand>(CommandType.SetTransformFeedbackBuffers);
+            Register<SetUniformBuffersCommand>(CommandType.SetUniformBuffers);
+            Register<SetImageCommand>(CommandType.SetImage);
+            Register<SetIndexBufferCommand>(CommandType.SetIndexBuffer);
+            Register<SetLineParametersCommand>(CommandType.SetLineParameters);
+            Register<SetLogicOpStateCommand>(CommandType.SetLogicOpState);
+            Register<SetMultisampleStateCommand>(CommandType.SetMultisampleState);
+            Register<SetPatchParametersCommand>(CommandType.SetPatchParameters);
+            Register<SetPointParametersCommand>(CommandType.SetPointParameters);
+            Register<SetPolygonModeCommand>(CommandType.SetPolygonMode);
+            Register<SetPrimitiveRestartCommand>(CommandType.SetPrimitiveRestart);
+            Register<SetPrimitiveTopologyCommand>(CommandType.SetPrimitiveTopology);
+            Register<SetProgramCommand>(CommandType.SetProgram);
+            Register<SetRasterizerDiscardCommand>(CommandType.SetRasterizerDiscard);
+            Register<SetRenderTargetColorMasksCommand>(CommandType.SetRenderTargetColorMasks);
+            Register<SetRenderTargetScaleCommand>(CommandType.SetRenderTargetScale);
+            Register<SetRenderTargetsCommand>(CommandType.SetRenderTargets);
+            Register<SetScissorsCommand>(CommandType.SetScissor);
+            Register<SetStencilTestCommand>(CommandType.SetStencilTest);
+            Register<SetTextureAndSamplerCommand>(CommandType.SetTextureAndSampler);
+            Register<SetUserClipDistanceCommand>(CommandType.SetUserClipDistance);
+            Register<SetVertexAttribsCommand>(CommandType.SetVertexAttribs);
+            Register<SetVertexBuffersCommand>(CommandType.SetVertexBuffers);
+            Register<SetViewportsCommand>(CommandType.SetViewports);
+            Register<TextureBarrierCommand>(CommandType.TextureBarrier);
+            Register<TextureBarrierTiledCommand>(CommandType.TextureBarrierTiled);
+            Register<TryHostConditionalRenderingCommand>(CommandType.TryHostConditionalRendering);
+            Register<TryHostConditionalRenderingFlushCommand>(CommandType.TryHostConditionalRenderingFlush);
+            Register<UpdateRenderScaleCommand>(CommandType.UpdateRenderScale);
+
+            return maxCommandSize;
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/BarrierCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/BarrierCommand.cs
index f187c3c2..4f8e1b08 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/BarrierCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/BarrierCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct BarrierCommand : IGALCommand
+    struct BarrierCommand : IGALCommand, IGALCommand<BarrierCommand>
     {
         public CommandType CommandType => CommandType.Barrier;
 
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/BeginTransformFeedbackCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/BeginTransformFeedbackCommand.cs
index ea547d8b..50032635 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/BeginTransformFeedbackCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/BeginTransformFeedbackCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct BeginTransformFeedbackCommand : IGALCommand
+    struct BeginTransformFeedbackCommand : IGALCommand, IGALCommand<BeginTransformFeedbackCommand>
     {
         public CommandType CommandType => CommandType.BeginTransformFeedback;
         private PrimitiveTopology _topology;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Buffer/BufferDisposeCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Buffer/BufferDisposeCommand.cs
index 68167be0..5be42fff 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Buffer/BufferDisposeCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Buffer/BufferDisposeCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Buffer
 {
-    struct BufferDisposeCommand : IGALCommand
+    struct BufferDisposeCommand : IGALCommand, IGALCommand<BufferDisposeCommand>
     {
         public CommandType CommandType => CommandType.BufferDispose;
         private BufferHandle _buffer;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Buffer/BufferGetDataCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Buffer/BufferGetDataCommand.cs
index 786ed87c..d3a255e7 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Buffer/BufferGetDataCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Buffer/BufferGetDataCommand.cs
@@ -3,7 +3,7 @@ using System;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Buffer
 {
-    struct BufferGetDataCommand : IGALCommand
+    struct BufferGetDataCommand : IGALCommand, IGALCommand<BufferGetDataCommand>
     {
         public CommandType CommandType => CommandType.BufferGetData;
         private BufferHandle _buffer;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Buffer/BufferSetDataCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Buffer/BufferSetDataCommand.cs
index 6f39898e..dcb8c2f2 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Buffer/BufferSetDataCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Buffer/BufferSetDataCommand.cs
@@ -3,7 +3,7 @@ using System;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Buffer
 {
-    struct BufferSetDataCommand : IGALCommand
+    struct BufferSetDataCommand : IGALCommand, IGALCommand<BufferSetDataCommand>
     {
         public CommandType CommandType => CommandType.BufferSetData;
         private BufferHandle _buffer;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearBufferCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearBufferCommand.cs
index 2b194b46..1d70460a 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearBufferCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearBufferCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct ClearBufferCommand : IGALCommand
+    struct ClearBufferCommand : IGALCommand, IGALCommand<ClearBufferCommand>
     {
         public CommandType CommandType => CommandType.ClearBuffer;
         private BufferHandle _destination;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetColorCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetColorCommand.cs
index 00a5128a..f8c2bdfe 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetColorCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetColorCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct ClearRenderTargetColorCommand : IGALCommand
+    struct ClearRenderTargetColorCommand : IGALCommand, IGALCommand<ClearRenderTargetColorCommand>
     {
         public CommandType CommandType => CommandType.ClearRenderTargetColor;
         private int _index;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetDepthStencilCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetDepthStencilCommand.cs
index c9ebad21..ca86673e 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetDepthStencilCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetDepthStencilCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct ClearRenderTargetDepthStencilCommand : IGALCommand
+    struct ClearRenderTargetDepthStencilCommand : IGALCommand, IGALCommand<ClearRenderTargetDepthStencilCommand>
     {
         public CommandType CommandType => CommandType.ClearRenderTargetDepthStencil;
         private int _layer;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/CommandBufferBarrierCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/CommandBufferBarrierCommand.cs
index 8c828648..ad3ab0f8 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/CommandBufferBarrierCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/CommandBufferBarrierCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct CommandBufferBarrierCommand : IGALCommand
+    struct CommandBufferBarrierCommand : IGALCommand, IGALCommand<CommandBufferBarrierCommand>
     {
         public CommandType CommandType => CommandType.CommandBufferBarrier;
 
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/CopyBufferCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/CopyBufferCommand.cs
index e8f80d98..43111bce 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/CopyBufferCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/CopyBufferCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct CopyBufferCommand : IGALCommand
+    struct CopyBufferCommand : IGALCommand, IGALCommand<CopyBufferCommand>
     {
         public CommandType CommandType => CommandType.CopyBuffer;
         private BufferHandle _source;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/CounterEvent/CounterEventDisposeCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/CounterEvent/CounterEventDisposeCommand.cs
index ae634e6a..e5250212 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/CounterEvent/CounterEventDisposeCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/CounterEvent/CounterEventDisposeCommand.cs
@@ -3,7 +3,7 @@ using Ryujinx.Graphics.GAL.Multithreading.Resources;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.CounterEvent
 {
-    struct CounterEventDisposeCommand : IGALCommand
+    struct CounterEventDisposeCommand : IGALCommand, IGALCommand<CounterEventDisposeCommand>
     {
         public CommandType CommandType => CommandType.CounterEventDispose;
         private TableRef<ThreadedCounterEvent> _event;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/CounterEvent/CounterEventFlushCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/CounterEvent/CounterEventFlushCommand.cs
index e4ff4c18..608cf8f9 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/CounterEvent/CounterEventFlushCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/CounterEvent/CounterEventFlushCommand.cs
@@ -3,7 +3,7 @@ using Ryujinx.Graphics.GAL.Multithreading.Resources;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.CounterEvent
 {
-    struct CounterEventFlushCommand : IGALCommand
+    struct CounterEventFlushCommand : IGALCommand, IGALCommand<CounterEventFlushCommand>
     {
         public CommandType CommandType => CommandType.CounterEventFlush;
         private TableRef<ThreadedCounterEvent> _event;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/DispatchComputeCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/DispatchComputeCommand.cs
index 26c88062..29568837 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/DispatchComputeCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/DispatchComputeCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct DispatchComputeCommand : IGALCommand
+    struct DispatchComputeCommand : IGALCommand, IGALCommand<DispatchComputeCommand>
     {
         public CommandType CommandType => CommandType.DispatchCompute;
         private int _groupsX;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawCommand.cs
index ff27303a..804eaa49 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct DrawIndexedCommand : IGALCommand
+    struct DrawIndexedCommand : IGALCommand, IGALCommand<DrawIndexedCommand>
     {
         public CommandType CommandType => CommandType.DrawIndexed;
         private int _indexCount;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawIndexedCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawIndexedCommand.cs
index fc84819a..1b28afcd 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawIndexedCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawIndexedCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct DrawCommand : IGALCommand
+    struct DrawCommand : IGALCommand, IGALCommand<DrawCommand>
     {
         public CommandType CommandType => CommandType.Draw;
         private int _vertexCount;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawIndexedIndirectCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawIndexedIndirectCommand.cs
index 3a47e962..521b2f0c 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawIndexedIndirectCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawIndexedIndirectCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct DrawIndexedIndirectCommand : IGALCommand
+    struct DrawIndexedIndirectCommand : IGALCommand, IGALCommand<DrawIndexedIndirectCommand>
     {
         public CommandType CommandType => CommandType.DrawIndexedIndirect;
         private BufferRange _indirectBuffer;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawIndexedIndirectCountCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawIndexedIndirectCountCommand.cs
index 79d9792e..6bdf376d 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawIndexedIndirectCountCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawIndexedIndirectCountCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct DrawIndexedIndirectCountCommand : IGALCommand
+    struct DrawIndexedIndirectCountCommand : IGALCommand, IGALCommand<DrawIndexedIndirectCountCommand>
     {
         public CommandType CommandType => CommandType.DrawIndexedIndirectCount;
         private BufferRange _indirectBuffer;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawIndirectCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawIndirectCommand.cs
index 73414e44..e1947084 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawIndirectCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawIndirectCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct DrawIndirectCommand : IGALCommand
+    struct DrawIndirectCommand : IGALCommand, IGALCommand<DrawIndirectCommand>
     {
         public CommandType CommandType => CommandType.DrawIndirect;
         private BufferRange _indirectBuffer;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawIndirectCountCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawIndirectCountCommand.cs
index 96f60f4a..ef56ffb2 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawIndirectCountCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawIndirectCountCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct DrawIndirectCountCommand : IGALCommand
+    struct DrawIndirectCountCommand : IGALCommand, IGALCommand<DrawIndirectCountCommand>
     {
         public CommandType CommandType => CommandType.DrawIndirectCount;
         private BufferRange _indirectBuffer;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawTextureCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawTextureCommand.cs
index 41a852bb..b3e9c4b5 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawTextureCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/DrawTextureCommand.cs
@@ -3,7 +3,7 @@ using Ryujinx.Graphics.GAL.Multithreading.Resources;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct DrawTextureCommand : IGALCommand
+    struct DrawTextureCommand : IGALCommand, IGALCommand<DrawTextureCommand>
     {
         public CommandType CommandType => CommandType.DrawTexture;
         private TableRef<ITexture> _texture;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/EndHostConditionalRenderingCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/EndHostConditionalRenderingCommand.cs
index e0edd9ab..877af23b 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/EndHostConditionalRenderingCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/EndHostConditionalRenderingCommand.cs
@@ -1,10 +1,10 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct EndHostConditionalRenderingCommand : IGALCommand
+    struct EndHostConditionalRenderingCommand : IGALCommand, IGALCommand<EndHostConditionalRenderingCommand>
     {
         public CommandType CommandType => CommandType.EndHostConditionalRendering;
 
-        public static void Run(IRenderer renderer)
+        public static void Run(ref EndHostConditionalRenderingCommand command, ThreadedRenderer threaded, IRenderer renderer)
         {
             renderer.Pipeline.EndHostConditionalRendering();
         }
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/EndTransformFeedbackCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/EndTransformFeedbackCommand.cs
index 561996e3..33df325f 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/EndTransformFeedbackCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/EndTransformFeedbackCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct EndTransformFeedbackCommand : IGALCommand
+    struct EndTransformFeedbackCommand : IGALCommand, IGALCommand<EndTransformFeedbackCommand>
     {
         public CommandType CommandType => CommandType.EndTransformFeedback;
 
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/IGALCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/IGALCommand.cs
index 5fb04c80..ea831c8d 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/IGALCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/IGALCommand.cs
@@ -4,4 +4,9 @@
     {
         CommandType CommandType { get; }
     }
+
+    interface IGALCommand<T> where T : IGALCommand
+    {
+        abstract static void Run(ref T command, ThreadedRenderer threaded, IRenderer renderer);
+    }
 }
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Program/ProgramCheckLinkCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Program/ProgramCheckLinkCommand.cs
index 7ae887f4..f3662424 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Program/ProgramCheckLinkCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Program/ProgramCheckLinkCommand.cs
@@ -3,7 +3,7 @@ using Ryujinx.Graphics.GAL.Multithreading.Resources;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Program
 {
-    struct ProgramCheckLinkCommand : IGALCommand
+    struct ProgramCheckLinkCommand : IGALCommand, IGALCommand<ProgramCheckLinkCommand>
     {
         public CommandType CommandType => CommandType.ProgramCheckLink;
         private TableRef<ThreadedProgram> _program;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Program/ProgramDisposeCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Program/ProgramDisposeCommand.cs
index e614c392..d1ec4298 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Program/ProgramDisposeCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Program/ProgramDisposeCommand.cs
@@ -3,7 +3,7 @@ using Ryujinx.Graphics.GAL.Multithreading.Resources;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Program
 {
-    struct ProgramDisposeCommand : IGALCommand
+    struct ProgramDisposeCommand : IGALCommand, IGALCommand<ProgramDisposeCommand>
     {
         public CommandType CommandType => CommandType.ProgramDispose;
         private TableRef<ThreadedProgram> _program;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Program/ProgramGetBinaryCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Program/ProgramGetBinaryCommand.cs
index 92c0a6d6..16963245 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Program/ProgramGetBinaryCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Program/ProgramGetBinaryCommand.cs
@@ -3,7 +3,7 @@ using Ryujinx.Graphics.GAL.Multithreading.Resources;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Program
 {
-    struct ProgramGetBinaryCommand : IGALCommand
+    struct ProgramGetBinaryCommand : IGALCommand, IGALCommand<ProgramGetBinaryCommand>
     {
         public CommandType CommandType => CommandType.ProgramGetBinary;
         private TableRef<ThreadedProgram> _program;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/ActionCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/ActionCommand.cs
index 07e55c96..41987da1 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/ActionCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/ActionCommand.cs
@@ -3,7 +3,7 @@ using System;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
 {
-    struct ActionCommand : IGALCommand
+    struct ActionCommand : IGALCommand, IGALCommand<ActionCommand>
     {
         public CommandType CommandType => CommandType.Action;
         private TableRef<Action> _action;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateBufferCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateBufferCommand.cs
index a96b3cef..4f01dea2 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateBufferCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateBufferCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
 {
-    struct CreateBufferCommand : IGALCommand
+    struct CreateBufferCommand : IGALCommand, IGALCommand<CreateBufferCommand>
     {
         public CommandType CommandType => CommandType.CreateBuffer;
         private BufferHandle _threadedHandle;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateProgramCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateProgramCommand.cs
index e24505e5..19563e12 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateProgramCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateProgramCommand.cs
@@ -3,7 +3,7 @@ using Ryujinx.Graphics.GAL.Multithreading.Resources.Programs;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
 {
-    struct CreateProgramCommand : IGALCommand
+    struct CreateProgramCommand : IGALCommand, IGALCommand<CreateProgramCommand>
     {
         public CommandType CommandType => CommandType.CreateProgram;
         private TableRef<IProgramRequest> _request;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateSamplerCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateSamplerCommand.cs
index bca98cfb..6ab862d4 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateSamplerCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateSamplerCommand.cs
@@ -3,7 +3,7 @@ using Ryujinx.Graphics.GAL.Multithreading.Resources;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
 {
-    struct CreateSamplerCommand : IGALCommand
+    struct CreateSamplerCommand : IGALCommand, IGALCommand<CreateSamplerCommand>
     {
         public CommandType CommandType => CommandType.CreateSampler;
         private TableRef<ThreadedSampler> _sampler;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateSyncCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateSyncCommand.cs
index 66f5cf06..32afb051 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateSyncCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateSyncCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
 {
-    struct CreateSyncCommand : IGALCommand
+    struct CreateSyncCommand : IGALCommand, IGALCommand<CreateSyncCommand>
     {
         public CommandType CommandType => CommandType.CreateSync;
         private ulong _id;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateTextureCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateTextureCommand.cs
index f9240125..0347ded4 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateTextureCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/CreateTextureCommand.cs
@@ -3,7 +3,7 @@ using Ryujinx.Graphics.GAL.Multithreading.Resources;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
 {
-    struct CreateTextureCommand : IGALCommand
+    struct CreateTextureCommand : IGALCommand, IGALCommand<CreateTextureCommand>
     {
         public CommandType CommandType => CommandType.CreateTexture;
         private TableRef<ThreadedTexture> _texture;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/GetCapabilitiesCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/GetCapabilitiesCommand.cs
index 102ed9da..4111dcfd 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/GetCapabilitiesCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/GetCapabilitiesCommand.cs
@@ -2,7 +2,7 @@
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
 {
-    struct GetCapabilitiesCommand : IGALCommand
+    struct GetCapabilitiesCommand : IGALCommand, IGALCommand<GetCapabilitiesCommand>
     {
         public CommandType CommandType => CommandType.GetCapabilities;
         private TableRef<ResultBox<Capabilities>> _result;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/PreFrameCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/PreFrameCommand.cs
index 1048dc9e..820908f3 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/PreFrameCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/PreFrameCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
 {
-    struct PreFrameCommand : IGALCommand
+    struct PreFrameCommand : IGALCommand, IGALCommand<PreFrameCommand>
     {
         public CommandType CommandType => CommandType.PreFrame;
 
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/ReportCounterCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/ReportCounterCommand.cs
index d477f235..4b0210cb 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/ReportCounterCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/ReportCounterCommand.cs
@@ -4,7 +4,7 @@ using System;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
 {
-    struct ReportCounterCommand : IGALCommand
+    struct ReportCounterCommand : IGALCommand, IGALCommand<ReportCounterCommand>
     {
         public CommandType CommandType => CommandType.ReportCounter;
         private TableRef<ThreadedCounterEvent> _event;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/ResetCounterCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/ResetCounterCommand.cs
index 2835bf31..3d796041 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/ResetCounterCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/ResetCounterCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
 {
-    struct ResetCounterCommand : IGALCommand
+    struct ResetCounterCommand : IGALCommand, IGALCommand<ResetCounterCommand>
     {
         public CommandType CommandType => CommandType.ResetCounter;
         private CounterType _type;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/UpdateCountersCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/UpdateCountersCommand.cs
index f28bf080..c7076c0e 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/UpdateCountersCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Renderer/UpdateCountersCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Renderer
 {
-    struct UpdateCountersCommand : IGALCommand
+    struct UpdateCountersCommand : IGALCommand, IGALCommand<UpdateCountersCommand>
     {
         public CommandType CommandType => CommandType.UpdateCounters;
 
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Sampler/SamplerDisposeCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Sampler/SamplerDisposeCommand.cs
index 8f4dfb7e..9485e9a1 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Sampler/SamplerDisposeCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Sampler/SamplerDisposeCommand.cs
@@ -3,7 +3,7 @@ using Ryujinx.Graphics.GAL.Multithreading.Resources;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Sampler
 {
-    struct SamplerDisposeCommand : IGALCommand
+    struct SamplerDisposeCommand : IGALCommand, IGALCommand<SamplerDisposeCommand>
     {
         public CommandType CommandType => CommandType.SamplerDispose;
         private TableRef<ThreadedSampler> _sampler;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetAlphaTestCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetAlphaTestCommand.cs
index 89379387..a96879ff 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetAlphaTestCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetAlphaTestCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetAlphaTestCommand : IGALCommand
+    struct SetAlphaTestCommand : IGALCommand, IGALCommand<SetAlphaTestCommand>
     {
         public CommandType CommandType => CommandType.SetAlphaTest;
         private bool _enable;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetBlendStateCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetBlendStateCommand.cs
index 6cc4894e..68e48da5 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetBlendStateCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetBlendStateCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetBlendStateCommand : IGALCommand
+    struct SetBlendStateCommand : IGALCommand, IGALCommand<SetBlendStateCommand>
     {
         public CommandType CommandType => CommandType.SetBlendState;
         private int _index;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetDepthBiasCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetDepthBiasCommand.cs
index 352242a3..eb8d4a72 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetDepthBiasCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetDepthBiasCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetDepthBiasCommand : IGALCommand
+    struct SetDepthBiasCommand : IGALCommand, IGALCommand<SetDepthBiasCommand>
     {
         public CommandType CommandType => CommandType.SetDepthBias;
         private PolygonModeMask _enables;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetDepthClampCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetDepthClampCommand.cs
index 21c8f3e6..15159cb4 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetDepthClampCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetDepthClampCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetDepthClampCommand : IGALCommand
+    struct SetDepthClampCommand : IGALCommand, IGALCommand<SetDepthClampCommand>
     {
         public CommandType CommandType => CommandType.SetDepthClamp;
         private bool _clamp;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetDepthModeCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetDepthModeCommand.cs
index 28c36be8..3e169164 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetDepthModeCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetDepthModeCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetDepthModeCommand : IGALCommand
+    struct SetDepthModeCommand : IGALCommand, IGALCommand<SetDepthModeCommand>
     {
         public CommandType CommandType => CommandType.SetDepthMode;
         private DepthMode _mode;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetDepthTestCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetDepthTestCommand.cs
index 585d3e8b..2abaeb78 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetDepthTestCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetDepthTestCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetDepthTestCommand : IGALCommand
+    struct SetDepthTestCommand : IGALCommand, IGALCommand<SetDepthTestCommand>
     {
         public CommandType CommandType => CommandType.SetDepthTest;
         private DepthTestDescriptor _depthTest;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetFaceCullingCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetFaceCullingCommand.cs
index 2a2b41ca..54311e95 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetFaceCullingCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetFaceCullingCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetFaceCullingCommand : IGALCommand
+    struct SetFaceCullingCommand : IGALCommand, IGALCommand<SetFaceCullingCommand>
     {
         public CommandType CommandType => CommandType.SetFaceCulling;
         private bool _enable;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetFrontFaceCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetFrontFaceCommand.cs
index a415237f..e4d7b814 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetFrontFaceCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetFrontFaceCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetFrontFaceCommand : IGALCommand
+    struct SetFrontFaceCommand : IGALCommand, IGALCommand<SetFrontFaceCommand>
     {
         public CommandType CommandType => CommandType.SetFrontFace;
         private FrontFace _frontFace;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageCommand.cs
index 4223a621..7836acd7 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetImageCommand.cs
@@ -3,7 +3,7 @@ using Ryujinx.Graphics.GAL.Multithreading.Resources;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetImageCommand : IGALCommand
+    struct SetImageCommand : IGALCommand, IGALCommand<SetImageCommand>
     {
         public CommandType CommandType => CommandType.SetImage;
         private int _binding;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetIndexBufferCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetIndexBufferCommand.cs
index 753e21f9..ded44c55 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetIndexBufferCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetIndexBufferCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetIndexBufferCommand : IGALCommand
+    struct SetIndexBufferCommand : IGALCommand, IGALCommand<SetIndexBufferCommand>
     {
         public CommandType CommandType => CommandType.SetIndexBuffer;
         private BufferRange _buffer;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetLineParametersCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetLineParametersCommand.cs
index 7fd2e5b1..68331932 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetLineParametersCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetLineParametersCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetLineParametersCommand : IGALCommand
+    struct SetLineParametersCommand : IGALCommand, IGALCommand<SetLineParametersCommand>
     {
         public CommandType CommandType => CommandType.SetLineParameters;
         private float _width;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetLogicOpStateCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetLogicOpStateCommand.cs
index 253ef138..2d7fc169 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetLogicOpStateCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetLogicOpStateCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetLogicOpStateCommand : IGALCommand
+    struct SetLogicOpStateCommand : IGALCommand, IGALCommand<SetLogicOpStateCommand>
     {
         public CommandType CommandType => CommandType.SetLogicOpState;
         private bool _enable;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetMultisampleStateCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetMultisampleStateCommand.cs
index f981c6ce..f7b4969a 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetMultisampleStateCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetMultisampleStateCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetMultisampleStateCommand : IGALCommand
+    struct SetMultisampleStateCommand : IGALCommand, IGALCommand<SetMultisampleStateCommand>
     {
         public CommandType CommandType => CommandType.SetMultisampleState;
         private MultisampleDescriptor _multisample;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetPatchParametersCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetPatchParametersCommand.cs
index d67cfc69..815bc3c2 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetPatchParametersCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetPatchParametersCommand.cs
@@ -3,7 +3,7 @@ using System;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetPatchParametersCommand : IGALCommand
+    struct SetPatchParametersCommand : IGALCommand, IGALCommand<SetPatchParametersCommand>
     {
         public CommandType CommandType => CommandType.SetPatchParameters;
         private int _vertices;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetPointParametersCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetPointParametersCommand.cs
index 37833a0e..e3fad0f8 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetPointParametersCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetPointParametersCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetPointParametersCommand : IGALCommand
+    struct SetPointParametersCommand : IGALCommand, IGALCommand<SetPointParametersCommand>
     {
         public CommandType CommandType => CommandType.SetPointParameters;
         private float _size;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetPolygonModeCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetPolygonModeCommand.cs
index 6de78f04..ea2f838b 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetPolygonModeCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetPolygonModeCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetPolygonModeCommand : IGALCommand
+    struct SetPolygonModeCommand : IGALCommand, IGALCommand<SetPolygonModeCommand>
     {
         public CommandType CommandType => CommandType.SetPolygonMode;
         private PolygonMode _frontMode;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetPrimitiveRestartCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetPrimitiveRestartCommand.cs
index e5f6ecf3..26b88b01 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetPrimitiveRestartCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetPrimitiveRestartCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetPrimitiveRestartCommand : IGALCommand
+    struct SetPrimitiveRestartCommand : IGALCommand, IGALCommand<SetPrimitiveRestartCommand>
     {
         public CommandType CommandType => CommandType.SetPrimitiveRestart;
         private bool _enable;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetPrimitiveTopologyCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetPrimitiveTopologyCommand.cs
index 0bf29260..062c4e57 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetPrimitiveTopologyCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetPrimitiveTopologyCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetPrimitiveTopologyCommand : IGALCommand
+    struct SetPrimitiveTopologyCommand : IGALCommand, IGALCommand<SetPrimitiveTopologyCommand>
     {
         public CommandType CommandType => CommandType.SetPrimitiveTopology;
         private PrimitiveTopology _topology;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetProgramCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetProgramCommand.cs
index c35d9c1f..fa2e9a8a 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetProgramCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetProgramCommand.cs
@@ -3,7 +3,7 @@ using Ryujinx.Graphics.GAL.Multithreading.Resources;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetProgramCommand : IGALCommand
+    struct SetProgramCommand : IGALCommand, IGALCommand<SetProgramCommand>
     {
         public CommandType CommandType => CommandType.SetProgram;
         private TableRef<IProgram> _program;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetRasterizerDiscardCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetRasterizerDiscardCommand.cs
index 4f92ce99..d2095a4f 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetRasterizerDiscardCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetRasterizerDiscardCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetRasterizerDiscardCommand : IGALCommand
+    struct SetRasterizerDiscardCommand : IGALCommand, IGALCommand<SetRasterizerDiscardCommand>
     {
         public CommandType CommandType => CommandType.SetRasterizerDiscard;
         private bool _discard;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetRenderTargetColorMasksCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetRenderTargetColorMasksCommand.cs
index 1e75ddb8..c247ff3a 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetRenderTargetColorMasksCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetRenderTargetColorMasksCommand.cs
@@ -3,7 +3,7 @@ using System;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetRenderTargetColorMasksCommand : IGALCommand
+    struct SetRenderTargetColorMasksCommand : IGALCommand, IGALCommand<SetRenderTargetColorMasksCommand>
     {
         public CommandType CommandType => CommandType.SetRenderTargetColorMasks;
         private SpanRef<uint> _componentMask;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetRenderTargetScaleCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetRenderTargetScaleCommand.cs
index a97a63db..7cb5ec11 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetRenderTargetScaleCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetRenderTargetScaleCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetRenderTargetScaleCommand : IGALCommand
+    struct SetRenderTargetScaleCommand : IGALCommand, IGALCommand<SetRenderTargetScaleCommand>
     {
         public CommandType CommandType => CommandType.SetRenderTargetScale;
         private float _scale;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetRenderTargetsCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetRenderTargetsCommand.cs
index 30f798dd..0b175a72 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetRenderTargetsCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetRenderTargetsCommand.cs
@@ -4,7 +4,7 @@ using System.Linq;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetRenderTargetsCommand : IGALCommand
+    struct SetRenderTargetsCommand : IGALCommand, IGALCommand<SetRenderTargetsCommand>
     {
         public CommandType CommandType => CommandType.SetRenderTargets;
         private TableRef<ITexture[]> _colors;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetScissorsCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetScissorsCommand.cs
index 6966df6d..985d775e 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetScissorsCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetScissorsCommand.cs
@@ -2,7 +2,7 @@
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetScissorsCommand : IGALCommand
+    struct SetScissorsCommand : IGALCommand, IGALCommand<SetScissorsCommand>
     {
         public CommandType CommandType => CommandType.SetScissor;
         private SpanRef<Rectangle<int>> _scissors;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetStencilTestCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetStencilTestCommand.cs
index cc5db4df..41bff97e 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetStencilTestCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetStencilTestCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetStencilTestCommand : IGALCommand
+    struct SetStencilTestCommand : IGALCommand, IGALCommand<SetStencilTestCommand>
     {
         public CommandType CommandType => CommandType.SetStencilTest;
         private StencilTestDescriptor _stencilTest;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetStorageBuffersCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetStorageBuffersCommand.cs
index 610603ca..6ecb0989 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetStorageBuffersCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetStorageBuffersCommand.cs
@@ -3,7 +3,7 @@ using System;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetStorageBuffersCommand : IGALCommand
+    struct SetStorageBuffersCommand : IGALCommand, IGALCommand<SetStorageBuffersCommand>
     {
         public CommandType CommandType => CommandType.SetStorageBuffers;
         private SpanRef<BufferAssignment> _buffers;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTextureAndSamplerCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTextureAndSamplerCommand.cs
index 7ef58c3d..5e8e0854 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTextureAndSamplerCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTextureAndSamplerCommand.cs
@@ -4,7 +4,7 @@ using Ryujinx.Graphics.Shader;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetTextureAndSamplerCommand : IGALCommand
+    struct SetTextureAndSamplerCommand : IGALCommand, IGALCommand<SetTextureAndSamplerCommand>
     {
         public CommandType CommandType => CommandType.SetTextureAndSampler;
         private ShaderStage _stage;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTransformFeedbackBuffersCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTransformFeedbackBuffersCommand.cs
index 5125447c..e0d4ef2d 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTransformFeedbackBuffersCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetTransformFeedbackBuffersCommand.cs
@@ -3,7 +3,7 @@ using System;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetTransformFeedbackBuffersCommand : IGALCommand
+    struct SetTransformFeedbackBuffersCommand : IGALCommand, IGALCommand<SetTransformFeedbackBuffersCommand>
     {
         public CommandType CommandType => CommandType.SetTransformFeedbackBuffers;
         private SpanRef<BufferRange> _buffers;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetUniformBuffersCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetUniformBuffersCommand.cs
index e4abb403..9e93db9e 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetUniformBuffersCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetUniformBuffersCommand.cs
@@ -3,7 +3,7 @@ using System;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetUniformBuffersCommand : IGALCommand
+    struct SetUniformBuffersCommand : IGALCommand, IGALCommand<SetUniformBuffersCommand>
     {
         public CommandType CommandType => CommandType.SetUniformBuffers;
         private SpanRef<BufferAssignment> _buffers;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetUserClipDistanceCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetUserClipDistanceCommand.cs
index f0f05779..4336ce49 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetUserClipDistanceCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetUserClipDistanceCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetUserClipDistanceCommand : IGALCommand
+    struct SetUserClipDistanceCommand : IGALCommand, IGALCommand<SetUserClipDistanceCommand>
     {
         public CommandType CommandType => CommandType.SetUserClipDistance;
         private int _index;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetVertexAttribsCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetVertexAttribsCommand.cs
index cbc313e9..e442c72d 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetVertexAttribsCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetVertexAttribsCommand.cs
@@ -3,7 +3,7 @@ using System;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetVertexAttribsCommand : IGALCommand
+    struct SetVertexAttribsCommand : IGALCommand, IGALCommand<SetVertexAttribsCommand>
     {
         public CommandType CommandType => CommandType.SetVertexAttribs;
         private SpanRef<VertexAttribDescriptor> _vertexAttribs;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetVertexBuffersCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetVertexBuffersCommand.cs
index b7d46d08..585da2a4 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetVertexBuffersCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetVertexBuffersCommand.cs
@@ -3,7 +3,7 @@ using System;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetVertexBuffersCommand : IGALCommand
+    struct SetVertexBuffersCommand : IGALCommand, IGALCommand<SetVertexBuffersCommand>
     {
         public CommandType CommandType => CommandType.SetVertexBuffers;
         private SpanRef<VertexBufferDescriptor> _vertexBuffers;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetViewportsCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetViewportsCommand.cs
index e1b8c7d4..c18bd811 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/SetViewportsCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/SetViewportsCommand.cs
@@ -3,7 +3,7 @@ using System;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct SetViewportsCommand : IGALCommand
+    struct SetViewportsCommand : IGALCommand, IGALCommand<SetViewportsCommand>
     {
         public CommandType CommandType => CommandType.SetViewports;
         private SpanRef<Viewport> _viewports;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureCopyToCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureCopyToCommand.cs
index 112c1fd1..02d0b639 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureCopyToCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureCopyToCommand.cs
@@ -3,7 +3,7 @@ using Ryujinx.Graphics.GAL.Multithreading.Resources;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
 {
-    struct TextureCopyToCommand : IGALCommand
+    struct TextureCopyToCommand : IGALCommand, IGALCommand<TextureCopyToCommand>
     {
         public CommandType CommandType => CommandType.TextureCopyTo;
         private TableRef<ThreadedTexture> _texture;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureCopyToScaledCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureCopyToScaledCommand.cs
index 11843361..6b83d3f8 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureCopyToScaledCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureCopyToScaledCommand.cs
@@ -3,7 +3,7 @@ using Ryujinx.Graphics.GAL.Multithreading.Resources;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
 {
-    struct TextureCopyToScaledCommand : IGALCommand
+    struct TextureCopyToScaledCommand : IGALCommand, IGALCommand<TextureCopyToScaledCommand>
     {
         public CommandType CommandType => CommandType.TextureCopyToScaled;
         private TableRef<ThreadedTexture> _texture;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureCopyToSliceCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureCopyToSliceCommand.cs
index 363edb00..2a340a70 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureCopyToSliceCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureCopyToSliceCommand.cs
@@ -3,7 +3,7 @@ using Ryujinx.Graphics.GAL.Multithreading.Resources;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
 {
-    struct TextureCopyToSliceCommand : IGALCommand
+    struct TextureCopyToSliceCommand : IGALCommand, IGALCommand<TextureCopyToSliceCommand>
     {
         public CommandType CommandType => CommandType.TextureCopyToSlice;
         private TableRef<ThreadedTexture> _texture;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureCreateViewCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureCreateViewCommand.cs
index 7c385407..09e9ca2f 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureCreateViewCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureCreateViewCommand.cs
@@ -3,7 +3,7 @@ using Ryujinx.Graphics.GAL.Multithreading.Resources;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
 {
-    struct TextureCreateViewCommand : IGALCommand
+    struct TextureCreateViewCommand : IGALCommand, IGALCommand<TextureCreateViewCommand>
     {
         public CommandType CommandType => CommandType.TextureCreateView;
         private TableRef<ThreadedTexture> _texture;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureGetDataCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureGetDataCommand.cs
index 9e7d0c64..1f519ccd 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureGetDataCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureGetDataCommand.cs
@@ -4,7 +4,7 @@ using System;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
 {
-    struct TextureGetDataCommand : IGALCommand
+    struct TextureGetDataCommand : IGALCommand, IGALCommand<TextureGetDataCommand>
     {
         public CommandType CommandType => CommandType.TextureGetData;
         private TableRef<ThreadedTexture> _texture;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureGetDataSliceCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureGetDataSliceCommand.cs
index 207e5784..5ac05971 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureGetDataSliceCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureGetDataSliceCommand.cs
@@ -4,7 +4,7 @@ using System;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
 {
-    struct TextureGetDataSliceCommand : IGALCommand
+    struct TextureGetDataSliceCommand : IGALCommand, IGALCommand<TextureGetDataSliceCommand>
     {
         public CommandType CommandType => CommandType.TextureGetDataSlice;
         private TableRef<ThreadedTexture> _texture;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureReleaseCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureReleaseCommand.cs
index 591b2214..61486e09 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureReleaseCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureReleaseCommand.cs
@@ -3,7 +3,7 @@ using Ryujinx.Graphics.GAL.Multithreading.Resources;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
 {
-    struct TextureReleaseCommand : IGALCommand
+    struct TextureReleaseCommand : IGALCommand, IGALCommand<TextureReleaseCommand>
     {
         public CommandType CommandType => CommandType.TextureRelease;
         private TableRef<ThreadedTexture> _texture;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataCommand.cs
index a8a6d274..cfbaffd3 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataCommand.cs
@@ -4,7 +4,7 @@ using System;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
 {
-    struct TextureSetDataCommand : IGALCommand
+    struct TextureSetDataCommand : IGALCommand, IGALCommand<TextureSetDataCommand>
     {
         public CommandType CommandType => CommandType.TextureSetData;
         private TableRef<ThreadedTexture> _texture;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceCommand.cs
index 0179ff11..a7126f61 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceCommand.cs
@@ -4,7 +4,7 @@ using System;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
 {
-    struct TextureSetDataSliceCommand : IGALCommand
+    struct TextureSetDataSliceCommand : IGALCommand, IGALCommand<TextureSetDataSliceCommand>
     {
         public CommandType CommandType => CommandType.TextureSetDataSlice;
         private TableRef<ThreadedTexture> _texture;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceRegionCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceRegionCommand.cs
index b4285592..4df83e08 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceRegionCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetDataSliceRegionCommand.cs
@@ -4,7 +4,7 @@ using System;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
 {
-    struct TextureSetDataSliceRegionCommand : IGALCommand
+    struct TextureSetDataSliceRegionCommand : IGALCommand, IGALCommand<TextureSetDataSliceRegionCommand>
     {
         public CommandType CommandType => CommandType.TextureSetDataSliceRegion;
         private TableRef<ThreadedTexture> _texture;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetStorageCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetStorageCommand.cs
index f86a9c44..2a1943a9 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetStorageCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Texture/TextureSetStorageCommand.cs
@@ -3,7 +3,7 @@ using Ryujinx.Graphics.GAL.Multithreading.Resources;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Texture
 {
-    struct TextureSetStorageCommand : IGALCommand
+    struct TextureSetStorageCommand : IGALCommand, IGALCommand<TextureSetStorageCommand>
     {
         public CommandType CommandType => CommandType.TextureSetStorage;
         private TableRef<ThreadedTexture> _texture;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/TextureBarrierCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/TextureBarrierCommand.cs
index b0b46021..ce1a83a7 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/TextureBarrierCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/TextureBarrierCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct TextureBarrierCommand : IGALCommand
+    struct TextureBarrierCommand : IGALCommand, IGALCommand<TextureBarrierCommand>
     {
         public CommandType CommandType => CommandType.TextureBarrier;
 
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/TextureBarrierTiledCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/TextureBarrierTiledCommand.cs
index f92abe5b..c65ffe2e 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/TextureBarrierTiledCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/TextureBarrierTiledCommand.cs
@@ -1,6 +1,6 @@
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct TextureBarrierTiledCommand : IGALCommand
+    struct TextureBarrierTiledCommand : IGALCommand, IGALCommand<TextureBarrierTiledCommand>
     {
         public CommandType CommandType => CommandType.TextureBarrierTiled;
 
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/TryHostConditionalRenderingCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/TryHostConditionalRenderingCommand.cs
index 65e1748d..9124ca1f 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/TryHostConditionalRenderingCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/TryHostConditionalRenderingCommand.cs
@@ -3,7 +3,7 @@ using Ryujinx.Graphics.GAL.Multithreading.Resources;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct TryHostConditionalRenderingCommand : IGALCommand
+    struct TryHostConditionalRenderingCommand : IGALCommand, IGALCommand<TryHostConditionalRenderingCommand>
     {
         public CommandType CommandType => CommandType.TryHostConditionalRendering;
         private TableRef<ThreadedCounterEvent> _value;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/TryHostConditionalRenderingFlushCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/TryHostConditionalRenderingFlushCommand.cs
index 29eb8dd4..a5d07640 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/TryHostConditionalRenderingFlushCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/TryHostConditionalRenderingFlushCommand.cs
@@ -3,7 +3,7 @@ using Ryujinx.Graphics.GAL.Multithreading.Resources;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct TryHostConditionalRenderingFlushCommand : IGALCommand
+    struct TryHostConditionalRenderingFlushCommand : IGALCommand, IGALCommand<TryHostConditionalRenderingFlushCommand>
     {
         public CommandType CommandType => CommandType.TryHostConditionalRenderingFlush;
         private TableRef<ThreadedCounterEvent> _value;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/UpdateRenderScaleCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/UpdateRenderScaleCommand.cs
index ca869b01..ebe14150 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/UpdateRenderScaleCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/UpdateRenderScaleCommand.cs
@@ -2,7 +2,7 @@
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands
 {
-    struct UpdateRenderScaleCommand : IGALCommand
+    struct UpdateRenderScaleCommand : IGALCommand, IGALCommand<UpdateRenderScaleCommand>
     {
         public CommandType CommandType => CommandType.UpdateRenderScale;
         private SpanRef<float> _scales;
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/Window/WindowPresentCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/Window/WindowPresentCommand.cs
index c4f3b553..6a24cd35 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/Window/WindowPresentCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/Window/WindowPresentCommand.cs
@@ -4,7 +4,7 @@ using System;
 
 namespace Ryujinx.Graphics.GAL.Multithreading.Commands.Window
 {
-    struct WindowPresentCommand : IGALCommand
+    struct WindowPresentCommand : IGALCommand, IGALCommand<WindowPresentCommand>
     {
         public CommandType CommandType => CommandType.WindowPresent;
         private TableRef<ThreadedTexture> _texture;