Просмотр исходного кода

Add per-source type memory change tracking, simplified state change tracking, other fixes

gdk 6 лет назад
Родитель
Сommit
8cba252b23
40 измененных файлов с 490 добавлено и 664 удалено
  1. 11 9
      ARMeilleure/Memory/MemoryManager.cs
  2. 5 3
      Ryujinx.Graphics.Gpu/Engine/Compute.cs
  3. 3 3
      Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs
  4. 8 9
      Ryujinx.Graphics.Gpu/Engine/MethodClear.cs
  5. 4 4
      Ryujinx.Graphics.Gpu/Engine/MethodCopyTexture.cs
  6. 7 7
      Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs
  7. 2 2
      Ryujinx.Graphics.Gpu/Engine/MethodReport.cs
  8. 6 6
      Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferBind.cs
  9. 1 1
      Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs
  10. 159 184
      Ryujinx.Graphics.Gpu/Engine/Methods.cs
  11. 2 1
      Ryujinx.Graphics.Gpu/Image/Pool.cs
  12. 1 1
      Ryujinx.Graphics.Gpu/Image/Texture.cs
  13. 1 1
      Ryujinx.Graphics.Gpu/Image/TextureManager.cs
  14. 1 1
      Ryujinx.Graphics.Gpu/Memory/Buffer.cs
  15. 6 2
      Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
  16. 1 1
      Ryujinx.Graphics.Gpu/Memory/IPhysicalMemory.cs
  17. 1 1
      Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs
  18. 10 0
      Ryujinx.Graphics.Gpu/Memory/ResourceName.cs
  19. 2 1
      Ryujinx.Graphics.Gpu/State/BlendState.cs
  20. 0 17
      Ryujinx.Graphics.Gpu/State/Bool.cs
  21. 12 0
      Ryujinx.Graphics.Gpu/State/Boolean32.cs
  22. 1 1
      Ryujinx.Graphics.Gpu/State/CopyTexture.cs
  23. 3 3
      Ryujinx.Graphics.Gpu/State/DepthBiasState.cs
  24. 1 1
      Ryujinx.Graphics.Gpu/State/FaceState.cs
  25. 58 328
      Ryujinx.Graphics.Gpu/State/GpuState.cs
  26. 56 0
      Ryujinx.Graphics.Gpu/State/GpuStateTable.cs
  27. 0 5
      Ryujinx.Graphics.Gpu/State/GpuVa.cs
  28. 71 58
      Ryujinx.Graphics.Gpu/State/MethodOffset.cs
  29. 2 2
      Ryujinx.Graphics.Gpu/State/PrimitiveRestartState.cs
  30. 8 0
      Ryujinx.Graphics.Gpu/State/RtColorState.cs
  31. 4 0
      Ryujinx.Graphics.Gpu/State/RtFormat.cs
  32. 8 0
      Ryujinx.Graphics.Gpu/State/ShaderState.cs
  33. 1 1
      Ryujinx.Graphics.Gpu/State/StencilBackTestState.cs
  34. 1 1
      Ryujinx.Graphics.Gpu/State/StencilTestState.cs
  35. 9 6
      Ryujinx.Graphics.OpenGL/Pipeline.cs
  36. 0 1
      Ryujinx.Graphics.Shader/Decoders/ImageComponents.cs
  37. 1 0
      Ryujinx.Graphics.Shader/Decoders/SystemRegister.cs
  38. 14 0
      Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs
  39. 7 1
      Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs
  40. 2 2
      Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/AddressSpaceContext.cs

+ 11 - 9
ARMeilleure/Memory/MemoryManager.cs

@@ -14,8 +14,6 @@ namespace ARMeilleure.Memory
         public const int PageSize = 1 << PageBits;
         public const int PageMask = PageSize - 1;
 
-        private const long PteFlagNotModified = 1;
-
         internal const long PteFlagsMask = 7;
 
         public IntPtr Ram { get; private set; }
@@ -106,6 +104,11 @@ namespace ARMeilleure.Memory
                 ptr = (byte*)ptrUlong;
             }
 
+            if (ptr == null)
+            {
+                return IntPtr.Zero;
+            }
+
             return new IntPtr(ptr + (position & PageMask));
         }
 
@@ -122,10 +125,7 @@ namespace ARMeilleure.Memory
 
             if ((ptrUlong & PteFlagsMask) != 0)
             {
-                if ((ptrUlong & PteFlagNotModified) != 0)
-                {
-                    ClearPtEntryFlag(position, PteFlagNotModified);
-                }
+                ClearPtEntryFlag(position, PteFlagsMask);
 
                 ptrUlong &= ~(ulong)PteFlagsMask;
 
@@ -253,8 +253,10 @@ namespace ARMeilleure.Memory
             return ptePtr;
         }
 
-        public unsafe (ulong, ulong)[] GetModifiedRanges(ulong address, ulong size)
+        public unsafe (ulong, ulong)[] GetModifiedRanges(ulong address, ulong size, int id)
         {
+            ulong idMask = 1UL << id;
+
             List<(ulong, ulong)> ranges = new List<(ulong, ulong)>();
 
             ulong endAddress = (address + size + PageMask) & ~(ulong)PageMask;
@@ -272,12 +274,12 @@ namespace ARMeilleure.Memory
 
                     ulong ptrUlong = (ulong)ptr;
 
-                    if ((ptrUlong & PteFlagNotModified) == 0)
+                    if ((ptrUlong & idMask) == 0)
                     {
                         // Modified.
                         currSize += PageSize;
 
-                        SetPtEntryFlag((long)address, PteFlagNotModified);
+                        SetPtEntryFlag((long)address, (long)idMask);
                     }
                     else
                     {

+ 5 - 3
Ryujinx.Graphics.Gpu/Engine/Compute.cs

@@ -27,15 +27,15 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
             _context.Renderer.Pipeline.BindProgram(cs.Interface);
 
-            PoolState samplerPool = _context.State.GetSamplerPoolState();
+            var samplerPool = _context.State.Get<PoolState>(MethodOffset.SamplerPoolState);
 
             _textureManager.SetComputeSamplerPool(samplerPool.Address.Pack(), samplerPool.MaximumId);
 
-            PoolState texturePool = _context.State.GetTexturePoolState();
+            var texturePool = _context.State.Get<PoolState>(MethodOffset.TexturePoolState);
 
             _textureManager.SetComputeTexturePool(texturePool.Address.Pack(), texturePool.MaximumId);
 
-            _textureManager.SetComputeTextureBufferIndex(_context.State.GetTextureBufferIndex());
+            _textureManager.SetComputeTextureBufferIndex(_context.State.Get<int>(MethodOffset.TextureBufferIndex));
 
             ShaderProgramInfo info = cs.Shader.Info;
 
@@ -117,6 +117,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
                 dispatchParams.UnpackGridSizeX(),
                 dispatchParams.UnpackGridSizeY(),
                 dispatchParams.UnpackGridSizeZ());
+
+            UpdateShaderState();
         }
     }
 }

+ 3 - 3
Ryujinx.Graphics.Gpu/Engine/Inline2Memory.cs

@@ -12,9 +12,9 @@ namespace Ryujinx.Graphics.Gpu.Engine
         private int _offset;
         private int _size;
 
-        public void Execute(int argument)
+        public void LaunchDma(int argument)
         {
-            _params = _context.State.Get<Inline2MemoryParams>(MethodOffset.Inline2MemoryParams);
+            _params = _context.State.Get<Inline2MemoryParams>(MethodOffset.I2mParams);
 
             _isLinear = (argument & 1) != 0;
 
@@ -22,7 +22,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
             _size   = _params.LineLengthIn * _params.LineCount;
         }
 
-        public void PushData(int argument)
+        public void LoadInlineData(int argument)
         {
             if (_isLinear)
             {

+ 8 - 9
Ryujinx.Graphics.Gpu/Engine/MethodClear.cs

@@ -7,7 +7,9 @@ namespace Ryujinx.Graphics.Gpu.Engine
     {
         private void Clear(int argument)
         {
-            UpdateState();
+            UpdateRenderTargetStateIfNeeded();
+
+            _textureManager.CommitGraphicsBindings();
 
             bool clearDepth   = (argument & 1) != 0;
             bool clearStencil = (argument & 2) != 0;
@@ -18,7 +20,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
             if (componentMask != 0)
             {
-                ClearColors clearColor = _context.State.GetClearColors();
+                var clearColor = _context.State.Get<ClearColors>(MethodOffset.ClearColors);
 
                 ColorF color = new ColorF(
                     clearColor.Red,
@@ -26,22 +28,19 @@ namespace Ryujinx.Graphics.Gpu.Engine
                     clearColor.Blue,
                     clearColor.Alpha);
 
-                _context.Renderer.Pipeline.ClearRenderTargetColor(
-                    index,
-                    componentMask,
-                    color);
+                _context.Renderer.Pipeline.ClearRenderTargetColor(index, componentMask, color);
             }
 
             if (clearDepth || clearStencil)
             {
-                float depthValue   = _context.State.GetClearDepthValue();
-                int   stencilValue = _context.State.GetClearStencilValue();
+                float depthValue   = _context.State.Get<float>(MethodOffset.ClearDepthValue);
+                int   stencilValue = _context.State.Get<int>  (MethodOffset.ClearStencilValue);
 
                 int stencilMask = 0;
 
                 if (clearStencil)
                 {
-                    stencilMask = _context.State.GetStencilTestState().FrontMask;
+                    stencilMask = _context.State.Get<StencilTestState>(MethodOffset.StencilTestState).FrontMask;
                 }
 
                 _context.Renderer.Pipeline.ClearRenderTargetDepthStencil(

+ 4 - 4
Ryujinx.Graphics.Gpu/Engine/MethodCopyTexture.cs

@@ -7,8 +7,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
     {
         private void CopyTexture(int argument)
         {
-            CopyTexture dstCopyTexture = _context.State.GetCopyDstTexture();
-            CopyTexture srcCopyTexture = _context.State.GetCopySrcTexture();
+            var dstCopyTexture = _context.State.Get<CopyTexture>(MethodOffset.CopyDstTexture);
+            var srcCopyTexture = _context.State.Get<CopyTexture>(MethodOffset.CopySrcTexture);
 
             Image.Texture srcTexture = _textureManager.FindOrCreateTexture(srcCopyTexture);
 
@@ -32,9 +32,9 @@ namespace Ryujinx.Graphics.Gpu.Engine
                 return;
             }
 
-            CopyTextureControl control = _context.State.GetCopyTextureControl();
+            var control = _context.State.Get<CopyTextureControl>(MethodOffset.CopyTextureControl);
 
-            CopyRegion region = _context.State.GetCopyRegion();
+            var region = _context.State.Get<CopyRegion>(MethodOffset.CopyRegion);
 
             int srcX1 = (int)(region.SrcXF >> 32);
             int srcY1 = (int)(region.SrcYF >> 32);

+ 7 - 7
Ryujinx.Graphics.Gpu/Engine/MethodDraw.cs

@@ -39,12 +39,12 @@ namespace Ryujinx.Graphics.Gpu.Engine
                     _instancedIndexed = _drawIndexed;
 
                     _instancedFirstIndex    = _firstIndex;
-                    _instancedFirstVertex   = _context.State.GetBaseVertex();
-                    _instancedFirstInstance = _context.State.GetBaseInstance();
+                    _instancedFirstVertex   = _context.State.Get<int>(MethodOffset.FirstVertex);
+                    _instancedFirstInstance = _context.State.Get<int>(MethodOffset.FirstInstance);
 
                     _instancedIndexCount = _indexCount;
 
-                    VertexBufferDrawState drawState = _context.State.GetVertexBufferDrawState();
+                    var drawState = _context.State.Get<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);
 
                     _instancedDrawStateFirst = drawState.First;
                     _instancedDrawStateCount = drawState.Count;
@@ -53,13 +53,13 @@ namespace Ryujinx.Graphics.Gpu.Engine
                 return;
             }
 
-            int firstInstance = _context.State.GetBaseInstance();
+            int firstInstance = _context.State.Get<int>(MethodOffset.FirstInstance);
 
             if (_drawIndexed)
             {
                 _drawIndexed = false;
 
-                int firstVertex = _context.State.GetBaseVertex();
+                int firstVertex = _context.State.Get<int>(MethodOffset.FirstVertex);
 
                 _context.Renderer.Pipeline.DrawIndexed(
                     _indexCount,
@@ -70,7 +70,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
             }
             else
             {
-                VertexBufferDrawState drawState = _context.State.GetVertexBufferDrawState();
+                var drawState = _context.State.Get<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);
 
                 _context.Renderer.Pipeline.Draw(
                     drawState.Count,
@@ -98,7 +98,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
             }
         }
 
-        private void SetIndexCount(int argument)
+        private void SetIndexBufferCount(int argument)
         {
             _drawIndexed = true;
         }

+ 2 - 2
Ryujinx.Graphics.Gpu/Engine/MethodReport.cs

@@ -25,7 +25,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
         private void ReportSemaphore()
         {
-            ReportState state = _context.State.GetReportState();
+            var state = _context.State.Get<ReportState>(MethodOffset.ReportState);
 
             _context.MemoryAccessor.Write(state.Address.Pack(), state.Payload);
 
@@ -78,7 +78,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
             Span<byte> data = MemoryMarshal.Cast<CounterData, byte>(counterDataSpan);
 
-            ReportState state = _context.State.GetReportState();
+            var state = _context.State.Get<ReportState>(MethodOffset.ReportState);
 
             _context.MemoryAccessor.Write(state.Address.Pack(), data);
         }

+ 6 - 6
Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferBind.cs

@@ -4,27 +4,27 @@ namespace Ryujinx.Graphics.Gpu.Engine
 {
     partial class Methods
     {
-        private void UniformBufferBind0(int argument)
+        private void UniformBufferBindVertex(int argument)
         {
             UniformBufferBind(argument, ShaderType.Vertex);
         }
 
-        private void UniformBufferBind1(int argument)
+        private void UniformBufferBindTessControl(int argument)
         {
             UniformBufferBind(argument, ShaderType.TessellationControl);
         }
 
-        private void UniformBufferBind2(int argument)
+        private void UniformBufferBindTessEvaluation(int argument)
         {
             UniformBufferBind(argument, ShaderType.TessellationEvaluation);
         }
 
-        private void UniformBufferBind3(int argument)
+        private void UniformBufferBindGeometry(int argument)
         {
             UniformBufferBind(argument, ShaderType.Geometry);
         }
 
-        private void UniformBufferBind4(int argument)
+        private void UniformBufferBindFragment(int argument)
         {
             UniformBufferBind(argument, ShaderType.Fragment);
         }
@@ -37,7 +37,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
             if (enable)
             {
-                UniformBufferState uniformBuffer = _context.State.GetUniformBufferState();
+                var uniformBuffer = _context.State.Get<UniformBufferState>(MethodOffset.UniformBufferState);
 
                 ulong address = uniformBuffer.Address.Pack();
 

+ 1 - 1
Ryujinx.Graphics.Gpu/Engine/MethodUniformBufferUpdate.cs

@@ -6,7 +6,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
     {
         private void UniformBufferUpdate(int argument)
         {
-            UniformBufferState uniformBuffer = _context.State.GetUniformBufferState();
+            var uniformBuffer = _context.State.Get<UniformBufferState>(MethodOffset.UniformBufferState);
 
             _context.MemoryAccessor.Write(uniformBuffer.Address.Pack() + (uint)uniformBuffer.Offset, argument);
 

+ 159 - 184
Ryujinx.Graphics.Gpu/Engine/Methods.cs

@@ -18,6 +18,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
         private ShaderCache _shaderCache;
 
+        private ShaderProgramInfo[] _currentProgramInfo;
+
         private BufferManager  _bufferManager;
         private TextureManager _textureManager;
 
@@ -33,6 +35,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
             _shaderCache = new ShaderCache(_context);
 
+            _currentProgramInfo = new ShaderProgramInfo[Constants.TotalShaderStages];
+
             _bufferManager  = new BufferManager(context);
             _textureManager = new TextureManager(context);
 
@@ -41,128 +45,184 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
         private void RegisterCallbacks()
         {
-            _context.State.RegisterCopyBufferCallback(CopyBuffer);
-            _context.State.RegisterCopyTextureCallback(CopyTexture);
-
-            _context.State.RegisterDrawEndCallback(DrawEnd);
-
-            _context.State.RegisterDrawBeginCallback(DrawBegin);
-
-            _context.State.RegisterSetIndexCountCallback(SetIndexCount);
+            _context.State.RegisterCallback(MethodOffset.LaunchDma,      LaunchDma);
+            _context.State.RegisterCallback(MethodOffset.LoadInlineData, LoadInlineData);
 
-            _context.State.RegisterClearCallback(Clear);
-
-            _context.State.RegisterReportCallback(Report);
-
-            _context.State.RegisterUniformBufferUpdateCallback(UniformBufferUpdate);
+            _context.State.RegisterCallback(MethodOffset.Dispatch, Dispatch);
 
-            _context.State.RegisterUniformBufferBind0Callback(UniformBufferBind0);
-            _context.State.RegisterUniformBufferBind1Callback(UniformBufferBind1);
-            _context.State.RegisterUniformBufferBind2Callback(UniformBufferBind2);
-            _context.State.RegisterUniformBufferBind3Callback(UniformBufferBind3);
-            _context.State.RegisterUniformBufferBind4Callback(UniformBufferBind4);
+            _context.State.RegisterCallback(MethodOffset.CopyBuffer,  CopyBuffer);
+            _context.State.RegisterCallback(MethodOffset.CopyTexture, CopyTexture);
 
             _context.State.RegisterCallback(MethodOffset.TextureBarrier,      TextureBarrier);
             _context.State.RegisterCallback(MethodOffset.InvalidateTextures,  InvalidateTextures);
             _context.State.RegisterCallback(MethodOffset.TextureBarrierTiled, TextureBarrierTiled);
 
-
             _context.State.RegisterCallback(MethodOffset.ResetCounter, ResetCounter);
 
-            _context.State.RegisterCallback(MethodOffset.Inline2MemoryExecute,  Execute);
-            _context.State.RegisterCallback(MethodOffset.Inline2MemoryPushData, PushData);
+            _context.State.RegisterCallback(MethodOffset.DrawEnd,   DrawEnd);
+            _context.State.RegisterCallback(MethodOffset.DrawBegin, DrawBegin);
 
-            _context.State.RegisterCallback(MethodOffset.Dispatch, Dispatch);
+            _context.State.RegisterCallback(MethodOffset.IndexBufferCount, SetIndexBufferCount);
+
+            _context.State.RegisterCallback(MethodOffset.Clear, Clear);
+
+            _context.State.RegisterCallback(MethodOffset.Report, Report);
+
+            _context.State.RegisterCallback(MethodOffset.UniformBufferUpdateData, 16, UniformBufferUpdate);
+
+            _context.State.RegisterCallback(MethodOffset.UniformBufferBindVertex,         UniformBufferBindVertex);
+            _context.State.RegisterCallback(MethodOffset.UniformBufferBindTessControl,    UniformBufferBindTessControl);
+            _context.State.RegisterCallback(MethodOffset.UniformBufferBindTessEvaluation, UniformBufferBindTessEvaluation);
+            _context.State.RegisterCallback(MethodOffset.UniformBufferBindGeometry,       UniformBufferBindGeometry);
+            _context.State.RegisterCallback(MethodOffset.UniformBufferBindFragment,       UniformBufferBindFragment);
         }
 
         public Image.Texture GetTexture(ulong address) => _textureManager.Find2(address);
 
         private void UpdateState()
         {
-            if ((_context.State.StateWriteFlags & StateWriteFlags.Any) == 0)
-            {
-                CommitBindings();
-
-                return;
-            }
-
             // Shaders must be the first one to be updated if modified, because
             // some of the other state depends on information from the currently
             // bound shaders.
-            if ((_context.State.StateWriteFlags & StateWriteFlags.ShaderState) != 0)
+            if (_context.State.QueryModified(MethodOffset.ShaderBaseAddress, MethodOffset.ShaderState))
             {
                 UpdateShaderState();
             }
 
-            if ((_context.State.StateWriteFlags & StateWriteFlags.RenderTargetGroup) != 0)
-            {
-                UpdateRenderTargetGroupState();
-            }
+            UpdateRenderTargetStateIfNeeded();
 
-            if ((_context.State.StateWriteFlags & StateWriteFlags.DepthTestState) != 0)
+            if (_context.State.QueryModified(MethodOffset.DepthTestEnable,
+                                             MethodOffset.DepthWriteEnable,
+                                             MethodOffset.DepthTestFunc))
             {
                 UpdateDepthTestState();
             }
 
-            if ((_context.State.StateWriteFlags & StateWriteFlags.ViewportTransform) != 0)
+            if (_context.State.QueryModified(MethodOffset.ViewportTransform, MethodOffset.ViewportExtents))
             {
                 UpdateViewportTransform();
             }
 
-            if ((_context.State.StateWriteFlags & StateWriteFlags.DepthBiasState) != 0)
+            if (_context.State.QueryModified(MethodOffset.DepthBiasState,
+                                             MethodOffset.DepthBiasFactor,
+                                             MethodOffset.DepthBiasUnits,
+                                             MethodOffset.DepthBiasClamp))
             {
                 UpdateDepthBiasState();
             }
 
-            if ((_context.State.StateWriteFlags & StateWriteFlags.StencilTestState) != 0)
+            if (_context.State.QueryModified(MethodOffset.StencilBackMasks,
+                                             MethodOffset.StencilTestState,
+                                             MethodOffset.StencilBackTestState))
             {
                 UpdateStencilTestState();
             }
 
-            if ((_context.State.StateWriteFlags & StateWriteFlags.SamplerPoolState) != 0)
+            // Pools.
+            if (_context.State.QueryModified(MethodOffset.SamplerPoolState))
             {
                 UpdateSamplerPoolState();
             }
 
-            if ((_context.State.StateWriteFlags & StateWriteFlags.TexturePoolState) != 0)
+            if (_context.State.QueryModified(MethodOffset.TexturePoolState))
             {
                 UpdateTexturePoolState();
             }
 
-            if ((_context.State.StateWriteFlags & StateWriteFlags.InputAssemblerGroup) != 0)
+            // Input assembler state.
+            if (_context.State.QueryModified(MethodOffset.VertexAttribState))
             {
-                UpdateInputAssemblerGroupState();
+                UpdateVertexAttribState();
+            }
+
+            if (_context.State.QueryModified(MethodOffset.PrimitiveRestartState))
+            {
+                UpdatePrimitiveRestartState();
+            }
+
+            if (_context.State.QueryModified(MethodOffset.IndexBufferState))
+            {
+                UpdateIndexBufferState();
+            }
+
+            if (_context.State.QueryModified(MethodOffset.VertexBufferDrawState,
+                                             MethodOffset.VertexBufferInstanced,
+                                             MethodOffset.VertexBufferState,
+                                             MethodOffset.VertexBufferEndAddress))
+            {
+                UpdateVertexBufferState();
             }
 
-            if ((_context.State.StateWriteFlags & StateWriteFlags.FaceState) != 0)
+            if (_context.State.QueryModified(MethodOffset.FaceState))
             {
                 UpdateFaceState();
             }
 
-            if ((_context.State.StateWriteFlags & StateWriteFlags.RtColorMask) != 0)
+            if (_context.State.QueryModified(MethodOffset.RtColorMask))
             {
                 UpdateRtColorMask();
             }
 
-            if ((_context.State.StateWriteFlags & StateWriteFlags.BlendState) != 0)
+            if (_context.State.QueryModified(MethodOffset.BlendEnable, MethodOffset.BlendState))
             {
                 UpdateBlendState();
             }
 
-            _context.State.StateWriteFlags &= ~StateWriteFlags.Any;
-
             CommitBindings();
         }
 
         private void CommitBindings()
         {
+            UpdateStorageBuffers();
+
             _bufferManager.CommitBindings();
             _textureManager.CommitGraphicsBindings();
         }
 
-        private void UpdateRenderTargetGroupState()
+        private void UpdateStorageBuffers()
+        {
+            for (int stage = 0; stage < _currentProgramInfo.Length; stage++)
+            {
+                ShaderProgramInfo info = _currentProgramInfo[stage];
+
+                if (info == null)
+                {
+                    continue;
+                }
+
+                for (int index = 0; index < info.SBuffers.Count; index++)
+                {
+                    BufferDescriptor sb = info.SBuffers[index];
+
+                    ulong sbDescAddress = _bufferManager.GetGraphicsUniformBufferAddress(stage, 0);
+
+                    int sbDescOffset = 0x110 + stage * 0x100 + sb.Slot * 0x10;
+
+                    sbDescAddress += (ulong)sbDescOffset;
+
+                    Span<byte> sbDescriptorData = _context.PhysicalMemory.Read(sbDescAddress, 0x10);
+
+                    SbDescriptor sbDescriptor = MemoryMarshal.Cast<byte, SbDescriptor>(sbDescriptorData)[0];
+
+                    _bufferManager.SetGraphicsStorageBuffer(stage, sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size);
+                }
+            }
+        }
+
+        private void UpdateRenderTargetStateIfNeeded()
+        {
+            if (_context.State.QueryModified(MethodOffset.RtColorState,
+                                             MethodOffset.RtDepthStencilState,
+                                             MethodOffset.RtDepthStencilSize,
+                                             MethodOffset.RtDepthStencilEnable))
+            {
+                UpdateRenderTargetState();
+            }
+        }
+
+        private void UpdateRenderTargetState()
         {
-            TextureMsaaMode msaaMode = _context.State.GetRtMsaaMode();
+            var msaaMode = _context.State.Get<TextureMsaaMode>(MethodOffset.RtMsaaMode);
 
             int samplesInX = msaaMode.SamplesInX();
             int samplesInY = msaaMode.SamplesInY();
@@ -173,7 +233,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
             {
                 for (int index = 0; index < Constants.TotalRenderTargets; index++)
                 {
-                    RtColorState colorState = _context.State.GetRtColorState(index);
+                    var colorState = _context.State.Get<RtColorState>(MethodOffset.RtColorState, index);
 
                     if (!IsRtEnabled(colorState))
                     {
@@ -189,7 +249,10 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
                     _textureManager.SetRenderTargetColor(index, color);
 
-                    color.Modified = true;
+                    if (color != null)
+                    {
+                        color.Modified = true;
+                    }
                 }
             }
             else
@@ -199,14 +262,14 @@ namespace Ryujinx.Graphics.Gpu.Engine
                 color3D.Modified = true;
             }
 
-            bool dsEnable = _context.State.Get<bool>(MethodOffset.RtDepthStencilEnable);
+            bool dsEnable = _context.State.Get<Boolean32>(MethodOffset.RtDepthStencilEnable);
 
             Image.Texture depthStencil = null;
 
             if (dsEnable)
             {
-                var dsState = _context.State.GetRtDepthStencilState();
-                var dsSize  = _context.State.GetRtDepthStencilSize();
+                var dsState = _context.State.Get<RtDepthStencilState>(MethodOffset.RtDepthStencilState);
+                var dsSize  = _context.State.Get<Size3D>             (MethodOffset.RtDepthStencilSize);
 
                 depthStencil = _textureManager.FindOrCreateTexture(
                     dsState,
@@ -216,11 +279,16 @@ namespace Ryujinx.Graphics.Gpu.Engine
             }
 
             _textureManager.SetRenderTargetDepthStencil(depthStencil);
+
+            if (depthStencil != null)
+            {
+                depthStencil.Modified = true;
+            }
         }
 
         private Image.Texture Get3DRenderTarget(int samplesInX, int samplesInY)
         {
-            RtColorState colorState0 = _context.State.GetRtColorState(0);
+            var colorState0 = _context.State.Get<RtColorState>(MethodOffset.RtColorState, 0);
 
             if (!IsRtEnabled(colorState0) || !colorState0.MemoryLayout.UnpackIsTarget3D() || colorState0.Depth != 1)
             {
@@ -232,7 +300,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
             for (int index = 1; index < Constants.TotalRenderTargets; index++)
             {
-                RtColorState colorState = _context.State.GetRtColorState(index);
+                var colorState = _context.State.Get<RtColorState>(MethodOffset.RtColorState, index);
 
                 if (!IsRtEnabled(colorState))
                 {
@@ -266,9 +334,9 @@ namespace Ryujinx.Graphics.Gpu.Engine
         private void UpdateDepthTestState()
         {
             _context.Renderer.Pipeline.SetDepthTest(new DepthTestDescriptor(
-                _context.State.GetDepthTestEnable().IsTrue(),
-                _context.State.GetDepthWriteEnable().IsTrue(),
-                _context.State.GetDepthTestFunc()));
+                _context.State.Get<Boolean32>(MethodOffset.DepthTestEnable),
+                _context.State.Get<Boolean32>(MethodOffset.DepthWriteEnable),
+                _context.State.Get<CompareOp>(MethodOffset.DepthTestFunc)));
         }
 
         private void UpdateViewportTransform()
@@ -277,8 +345,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
             for (int index = 0; index < Constants.TotalViewports; index++)
             {
-                var transform = _context.State.Get<ViewportTransform>(MethodOffset.ViewportTransform + index * 8);
-                var extents   = _context.State.Get<ViewportExtents>  (MethodOffset.ViewportExtents   + index * 4);
+                var transform = _context.State.Get<ViewportTransform>(MethodOffset.ViewportTransform, index);
+                var extents   = _context.State.Get<ViewportExtents>  (MethodOffset.ViewportExtents,   index);
 
                 float x = transform.TranslateX - MathF.Abs(transform.ScaleX);
                 float y = transform.TranslateY - MathF.Abs(transform.ScaleY);
@@ -303,7 +371,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
         private void UpdateDepthBiasState()
         {
-            var polygonOffset = _context.State.Get<DepthBiasState>(MethodOffset.DepthBiasState);
+            var depthBias = _context.State.Get<DepthBiasState>(MethodOffset.DepthBiasState);
 
             float factor = _context.State.Get<float>(MethodOffset.DepthBiasFactor);
             float units  = _context.State.Get<float>(MethodOffset.DepthBiasUnits);
@@ -311,18 +379,18 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
             PolygonModeMask enables = 0;
 
-            enables  = (polygonOffset.PointEnable.IsTrue() ? PolygonModeMask.Point : 0);
-            enables |= (polygonOffset.LineEnable.IsTrue()  ? PolygonModeMask.Line  : 0);
-            enables |= (polygonOffset.FillEnable.IsTrue()  ? PolygonModeMask.Fill  : 0);
+            enables  = (depthBias.PointEnable ? PolygonModeMask.Point : 0);
+            enables |= (depthBias.LineEnable  ? PolygonModeMask.Line  : 0);
+            enables |= (depthBias.FillEnable  ? PolygonModeMask.Fill  : 0);
 
             _context.Renderer.Pipeline.SetDepthBias(enables, factor, units, clamp);
         }
 
         private void UpdateStencilTestState()
         {
-            StencilBackMasks     backMasks = _context.State.GetStencilBackMasks();
-            StencilTestState     test      = _context.State.GetStencilTestState();
-            StencilBackTestState backTest  = _context.State.GetStencilBackTestState();
+            var backMasks = _context.State.Get<StencilBackMasks>    (MethodOffset.StencilBackMasks);
+            var test      = _context.State.Get<StencilTestState>    (MethodOffset.StencilTestState);
+            var backTest  = _context.State.Get<StencilBackTestState>(MethodOffset.StencilBackTestState);
 
             CompareOp backFunc;
             StencilOp backSFail;
@@ -332,7 +400,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
             int       backFuncMask;
             int       backMask;
 
-            if (backTest.TwoSided.IsTrue())
+            if (backTest.TwoSided)
             {
                 backFunc     = backTest.BackFunc;
                 backSFail    = backTest.BackSFail;
@@ -354,7 +422,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
             }
 
             _context.Renderer.Pipeline.SetStencilTest(new StencilTestDescriptor(
-                test.Enable.IsTrue(),
+                test.Enable,
                 test.FrontFunc,
                 test.FrontSFail,
                 test.FrontDpPass,
@@ -373,42 +441,18 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
         private void UpdateSamplerPoolState()
         {
-            PoolState samplerPool = _context.State.GetSamplerPoolState();
+            var samplerPool = _context.State.Get<PoolState>(MethodOffset.SamplerPoolState);
 
             _textureManager.SetGraphicsSamplerPool(samplerPool.Address.Pack(), samplerPool.MaximumId);
         }
 
         private void UpdateTexturePoolState()
         {
-            PoolState texturePool = _context.State.GetTexturePoolState();
+            var texturePool = _context.State.Get<PoolState>(MethodOffset.TexturePoolState);
 
             _textureManager.SetGraphicsTexturePool(texturePool.Address.Pack(), texturePool.MaximumId);
 
-            _textureManager.SetGraphicsTextureBufferIndex(_context.State.GetTextureBufferIndex());
-        }
-
-        private void UpdateInputAssemblerGroupState()
-        {
-            // Must be updated before the vertex buffer.
-            if ((_context.State.StateWriteFlags & StateWriteFlags.VertexAttribState) != 0)
-            {
-                UpdateVertexAttribState();
-            }
-
-            if ((_context.State.StateWriteFlags & StateWriteFlags.PrimitiveRestartState) != 0)
-            {
-                UpdatePrimitiveRestartState();
-            }
-
-            if ((_context.State.StateWriteFlags & StateWriteFlags.IndexBufferState) != 0)
-            {
-                UpdateIndexBufferState();
-            }
-
-            if ((_context.State.StateWriteFlags & StateWriteFlags.VertexBufferState) != 0)
-            {
-                UpdateVertexBufferState();
-            }
+            _textureManager.SetGraphicsTextureBufferIndex(_context.State.Get<int>(MethodOffset.TextureBufferIndex));
         }
 
         private void UpdateVertexAttribState()
@@ -417,7 +461,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
             for (int index = 0; index < 16; index++)
             {
-                VertexAttribState vertexAttrib = _context.State.GetVertexAttribState(index);
+                var vertexAttrib = _context.State.Get<VertexAttribState>(MethodOffset.VertexAttribState, index);
 
                 if (!FormatTable.TryGetAttribFormat(vertexAttrib.UnpackFormat(), out Format format))
                 {
@@ -446,7 +490,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
         private void UpdateIndexBufferState()
         {
-            IndexBufferState indexBuffer = _context.State.GetIndexBufferState();
+            var indexBuffer = _context.State.Get<IndexBufferState>(MethodOffset.IndexBufferState);
 
             _firstIndex = indexBuffer.First;
             _indexCount = indexBuffer.Count;
@@ -475,70 +519,13 @@ namespace Ryujinx.Graphics.Gpu.Engine
             UpdateVertexBufferState();
         }
 
-        private uint GetIndexBufferMaxIndex(ulong gpuVa, ulong size, IndexType type)
-        {
-            ulong address = _context.MemoryManager.Translate(gpuVa);
-
-            Span<byte> data = _context.PhysicalMemory.Read(address, size);
-
-            uint maxIndex = 0;
-
-            switch (type)
-            {
-                case IndexType.UByte:
-                {
-                    for (int index = 0; index < data.Length; index++)
-                    {
-                        if (maxIndex < data[index])
-                        {
-                            maxIndex = data[index];
-                        }
-                    }
-
-                    break;
-                }
-
-                case IndexType.UShort:
-                {
-                    Span<ushort> indices = MemoryMarshal.Cast<byte, ushort>(data);
-
-                    for (int index = 0; index < indices.Length; index++)
-                    {
-                        if (maxIndex < indices[index])
-                        {
-                            maxIndex = indices[index];
-                        }
-                    }
-
-                    break;
-                }
-
-                case IndexType.UInt:
-                {
-                    Span<uint> indices = MemoryMarshal.Cast<byte, uint>(data);
-
-                    for (int index = 0; index < indices.Length; index++)
-                    {
-                        if (maxIndex < indices[index])
-                        {
-                            maxIndex = indices[index];
-                        }
-                    }
-
-                    break;
-                }
-            }
-
-            return maxIndex;
-        }
-
         private void UpdateVertexBufferState()
         {
             _isAnyVbInstanced = false;
 
             for (int index = 0; index < 16; index++)
             {
-                VertexBufferState vertexBuffer = _context.State.GetVertexBufferState(index);
+                var vertexBuffer = _context.State.Get<VertexBufferState>(MethodOffset.VertexBufferState, index);
 
                 if (!vertexBuffer.UnpackEnable())
                 {
@@ -547,13 +534,13 @@ namespace Ryujinx.Graphics.Gpu.Engine
                     continue;
                 }
 
-                GpuVa endAddress = _context.State.GetVertexBufferEndAddress(index);
+                GpuVa endAddress = _context.State.Get<GpuVa>(MethodOffset.VertexBufferEndAddress, index);
 
                 ulong address = vertexBuffer.Address.Pack();
 
                 int stride = vertexBuffer.UnpackStride();
 
-                bool instanced = _context.State.Get<bool>(MethodOffset.VertexBufferInstanced + index);
+                bool instanced = _context.State.Get<Boolean32>(MethodOffset.VertexBufferInstanced + index);
 
                 int divisor = instanced ? vertexBuffer.Divisor : 0;
 
@@ -571,9 +558,9 @@ namespace Ryujinx.Graphics.Gpu.Engine
                 {
                     // For non-indexed draws, we can guess the size from the vertex count
                     // and stride.
-                    int firstInstance = _context.State.GetBaseInstance();
+                    int firstInstance = _context.State.Get<int>(MethodOffset.FirstInstance);
 
-                    VertexBufferDrawState drawState = _context.State.GetVertexBufferDrawState();
+                    var drawState = _context.State.Get<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);
 
                     size = (ulong)((firstInstance + drawState.First + drawState.Count) * stride);
                 }
@@ -584,9 +571,9 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
         private void UpdateFaceState()
         {
-            FaceState face = _context.State.GetFaceState();
+            var face = _context.State.Get<FaceState>(MethodOffset.FaceState);
 
-            _context.Renderer.Pipeline.SetFaceCulling(face.CullEnable.IsTrue(), face.CullFace);
+            _context.Renderer.Pipeline.SetFaceCulling(face.CullEnable, face.CullFace);
 
             _context.Renderer.Pipeline.SetFrontFace(face.FrontFace);
         }
@@ -597,7 +584,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
             for (int index = 0; index < Constants.TotalRenderTargets; index++)
             {
-                RtColorMask colorMask = _context.State.Get<RtColorMask>(MethodOffset.RtColorMask + index);
+                var colorMask = _context.State.Get<RtColorMask>(MethodOffset.RtColorMask, index);
 
                 uint componentMask = 0;
 
@@ -618,12 +605,12 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
             for (int index = 0; index < 8; index++)
             {
-                bool blendEnable = _context.State.GetBlendEnable(index).IsTrue();
+                bool enable = _context.State.Get<Boolean32>(MethodOffset.BlendEnable, index);
 
-                BlendState blend = _context.State.GetBlendState(index);
+                var blend = _context.State.Get<BlendState>(MethodOffset.BlendState, index);
 
                 BlendDescriptor descriptor = new BlendDescriptor(
-                    blendEnable,
+                    enable,
                     blend.ColorOp,
                     blend.ColorSrcFactor,
                     blend.ColorDstFactor,
@@ -656,11 +643,11 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
             Span<ulong> addressesArray = MemoryMarshal.Cast<ShaderAddresses, ulong>(addressesSpan);
 
-            ulong baseAddress = _context.State.GetShaderBaseAddress().Pack();
+            ulong baseAddress = _context.State.Get<GpuVa>(MethodOffset.ShaderBaseAddress).Pack();
 
             for (int index = 0; index < 6; index++)
             {
-                ShaderState shader = _context.State.GetShaderState(index);
+                var shader = _context.State.Get<ShaderState>(MethodOffset.ShaderState, index);
 
                 if (!shader.UnpackEnable() && index != 1)
                 {
@@ -678,6 +665,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
             {
                 ShaderProgramInfo info = gs.Shader[stage]?.Info;
 
+                _currentProgramInfo[stage] = info;
+
                 if (info == null)
                 {
                     continue;
@@ -714,21 +703,7 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
                 for (int index = 0; index < info.SBuffers.Count; index++)
                 {
-                    BufferDescriptor sb = info.SBuffers[index];
-
-                    sbEnableMask |= 1u << sb.Slot;
-
-                    ulong sbDescAddress = _bufferManager.GetGraphicsUniformBufferAddress(stage, 0);
-
-                    int sbDescOffset = 0x110 + stage * 0x100 + sb.Slot * 0x10;
-
-                    sbDescAddress += (ulong)sbDescOffset;
-
-                    Span<byte> sbDescriptorData = _context.PhysicalMemory.Read(sbDescAddress, 0x10);
-
-                    SbDescriptor sbDescriptor = MemoryMarshal.Cast<byte, SbDescriptor>(sbDescriptorData)[0];
-
-                    _bufferManager.SetGraphicsStorageBuffer(stage, sb.Slot, sbDescriptor.PackAddress(), (uint)sbDescriptor.Size);
+                    sbEnableMask |= 1u << info.SBuffers[index].Slot;
                 }
 
                 for (int index = 0; index < info.CBuffers.Count; index++)

+ 2 - 1
Ryujinx.Graphics.Gpu/Image/Pool.cs

@@ -1,3 +1,4 @@
+using Ryujinx.Graphics.Gpu.Memory;
 using System;
 
 namespace Ryujinx.Graphics.Gpu.Image
@@ -31,7 +32,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 
         public void SynchronizeMemory()
         {
-            (ulong, ulong)[] modifiedRanges = Context.PhysicalMemory.GetModifiedRanges(Address, Size);
+            (ulong, ulong)[] modifiedRanges = Context.PhysicalMemory.GetModifiedRanges(Address, Size, ResourceName.TexturePool);
 
             for (int index = 0; index < modifiedRanges.Length; index++)
             {

+ 1 - 1
Ryujinx.Graphics.Gpu/Image/Texture.cs

@@ -202,7 +202,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 
             _sequenceNumber = _context.SequenceNumber;
 
-            bool modified = _context.PhysicalMemory.GetModifiedRanges(Address, Size).Length != 0;
+            bool modified = _context.PhysicalMemory.GetModifiedRanges(Address, Size, ResourceName.Texture).Length != 0;
 
             if (!modified && _hasData)
             {

+ 1 - 1
Ryujinx.Graphics.Gpu/Image/TextureManager.cs

@@ -114,7 +114,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 
         public void CommitComputeBindings()
         {
-            // Evert time we switch between graphics and compute work,
+            // Every time we switch between graphics and compute work,
             // we must rebind everything.
             // Since compute work happens less often, we always do that
             // before and after the compute dispatch.

+ 1 - 1
Ryujinx.Graphics.Gpu/Memory/Buffer.cs

@@ -69,7 +69,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
                 return;
             }
 
-            (ulong, ulong)[] modifiedRanges = _context.PhysicalMemory.GetModifiedRanges(address, size);
+            (ulong, ulong)[] modifiedRanges = _context.PhysicalMemory.GetModifiedRanges(address, size, ResourceName.Buffer);
 
             for (int index = 0; index < modifiedRanges.Length; index++)
             {

+ 6 - 2
Ryujinx.Graphics.Gpu/Memory/BufferManager.cs

@@ -116,9 +116,13 @@ namespace Ryujinx.Graphics.Gpu.Memory
 
             ulong address = TranslateAndCreateBuffer(gpuVa, size);
 
-            _gpStorageBuffers[stage].Bind(index, address, size);
+            if (_gpStorageBuffers[stage].Buffers[index].Address != address ||
+                _gpStorageBuffers[stage].Buffers[index].Size    != size)
+            {
+                _gpStorageBuffersDirty = true;
+            }
 
-            _gpStorageBuffersDirty = true;
+            _gpStorageBuffers[stage].Bind(index, address, size);
         }
 
         public void SetComputeUniformBuffer(int index, ulong gpuVa, ulong size)

+ 1 - 1
Ryujinx.Graphics.Gpu/Memory/IPhysicalMemory.cs

@@ -10,6 +10,6 @@ namespace Ryujinx.Graphics.Gpu.Memory
 
         void Write(ulong address, Span<byte> data);
 
-        (ulong, ulong)[] GetModifiedRanges(ulong address, ulong size);
+        (ulong, ulong)[] GetModifiedRanges(ulong address, ulong size, ResourceName name);
     }
 }

+ 1 - 1
Ryujinx.Graphics.Gpu/Memory/MemoryManager.cs

@@ -8,7 +8,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
 
         private const int PtLvl0Bits = 14;
         private const int PtLvl1Bits = 14;
-        private const int PtPageBits = 12;
+        public  const int PtPageBits = 12;
 
         private const ulong PtLvl0Size = 1UL << PtLvl0Bits;
         private const ulong PtLvl1Size = 1UL << PtLvl1Bits;

+ 10 - 0
Ryujinx.Graphics.Gpu/Memory/ResourceName.cs

@@ -0,0 +1,10 @@
+namespace Ryujinx.Graphics.Gpu.Memory
+{
+    public enum ResourceName
+    {
+        Buffer,
+        Texture,
+        TexturePool,
+        SamplerPool
+    }
+}

+ 2 - 1
Ryujinx.Graphics.Gpu/State/BlendState.cs

@@ -4,12 +4,13 @@ namespace Ryujinx.Graphics.Gpu.State
 {
     struct BlendState
     {
-        public Bool        SeparateAlpha;
+        public Boolean32   SeparateAlpha;
         public BlendOp     ColorOp;
         public BlendFactor ColorSrcFactor;
         public BlendFactor ColorDstFactor;
         public BlendOp     AlphaOp;
         public BlendFactor AlphaSrcFactor;
         public BlendFactor AlphaDstFactor;
+        public uint        Padding;
     }
 }

+ 0 - 17
Ryujinx.Graphics.Gpu/State/Bool.cs

@@ -1,17 +0,0 @@
-namespace Ryujinx.Graphics.Gpu.State
-{
-    struct Bool
-    {
-        private uint _value;
-
-        public bool IsTrue()
-        {
-            return (_value & 1) != 0;
-        }
-
-        public bool IsFalse()
-        {
-            return (_value & 1) == 0;
-        }
-    }
-}

+ 12 - 0
Ryujinx.Graphics.Gpu/State/Boolean32.cs

@@ -0,0 +1,12 @@
+namespace Ryujinx.Graphics.Gpu.State
+{
+    struct Boolean32
+    {
+        private uint _value;
+
+        public static implicit operator bool(Boolean32 value)
+        {
+            return (value._value & 1) != 0;
+        }
+    }
+}

+ 1 - 1
Ryujinx.Graphics.Gpu/State/CopyTexture.cs

@@ -3,7 +3,7 @@ namespace Ryujinx.Graphics.Gpu.State
     struct CopyTexture
     {
         public RtFormat     Format;
-        public bool         LinearLayout;
+        public Boolean32    LinearLayout;
         public MemoryLayout MemoryLayout;
         public int          Depth;
         public int          Layer;

+ 3 - 3
Ryujinx.Graphics.Gpu/State/DepthBiasState.cs

@@ -2,8 +2,8 @@ namespace Ryujinx.Graphics.Gpu.State
 {
     struct DepthBiasState
     {
-        public Bool PointEnable;
-        public Bool LineEnable;
-        public Bool FillEnable;
+        public Boolean32 PointEnable;
+        public Boolean32 LineEnable;
+        public Boolean32 FillEnable;
     }
 }

+ 1 - 1
Ryujinx.Graphics.Gpu/State/FaceState.cs

@@ -4,7 +4,7 @@ namespace Ryujinx.Graphics.Gpu.State
 {
     struct FaceState
     {
-        public Bool      CullEnable;
+        public Boolean32 CullEnable;
         public FrontFace FrontFace;
         public Face      CullFace;
     }

+ 58 - 328
Ryujinx.Graphics.Gpu/State/GpuState.cs

@@ -1,6 +1,4 @@
-using Ryujinx.Graphics.GAL;
-using Ryujinx.Graphics.Gpu.Image;
-using System;
+using System;
 using System.Runtime.InteropServices;
 
 namespace Ryujinx.Graphics.Gpu.State
@@ -17,39 +15,54 @@ namespace Ryujinx.Graphics.Gpu.State
         {
             public MethodCallback Callback;
 
-            public StateWriteFlags WriteFlag;
+            public MethodOffset BaseOffset;
+
+            public int Stride;
+            public int Count;
+
+            public bool Modified;
         }
 
         private Register[] _registers;
 
-        public StateWriteFlags StateWriteFlags { get; set; }
-
         public GpuState()
         {
             _backingMemory = new int[RegistersCount];
 
             _registers = new Register[RegistersCount];
 
-            StateWriteFlags = StateWriteFlags.Any;
+            for (int index = 0; index < _registers.Length; index++)
+            {
+                _registers[index].BaseOffset = (MethodOffset)index;
+                _registers[index].Stride     = 1;
+                _registers[index].Count      = 1;
+                _registers[index].Modified   = true;
+            }
+
+            foreach (var item in GpuStateTable.Table)
+            {
+                int totalRegs = item.Size * item.Count;
+
+                for (int regOffset = 0; regOffset < totalRegs; regOffset++)
+                {
+                    int index = (int)item.Offset + regOffset;
+
+                    _registers[index].BaseOffset = item.Offset;
+                    _registers[index].Stride     = item.Size;
+                    _registers[index].Count      = item.Count;
+                }
+            }
 
             InitializeDefaultState();
-            InitializeStateWatchers();
         }
 
-        public bool ExitEarly;
-
         public void CallMethod(MethodParams meth)
         {
-            if (ExitEarly)
-            {
-                return;
-            }
-
             Register register = _registers[meth.Method];
 
             if (_backingMemory[meth.Method] != meth.Argument)
             {
-                StateWriteFlags |= register.WriteFlag;
+                _registers[(int)register.BaseOffset].Modified = true;
             }
 
             _backingMemory[meth.Method] = meth.Argument;
@@ -67,264 +80,11 @@ namespace Ryujinx.Graphics.Gpu.State
             return _backingMemory[offset];
         }
 
-        public void RegisterCopyBufferCallback(MethodCallback callback)
-        {
-            RegisterCallback(0xc0, callback);
-        }
-
-        public void RegisterCopyTextureCallback(MethodCallback callback)
-        {
-            RegisterCallback(0x237, callback);
-        }
-
-        public void RegisterDrawEndCallback(MethodCallback callback)
-        {
-            RegisterCallback(0x585, callback);
-        }
-
-        public void RegisterDrawBeginCallback(MethodCallback callback)
-        {
-            RegisterCallback(0x586, callback);
-        }
-
-        public void RegisterSetIndexCountCallback(MethodCallback callback)
-        {
-            RegisterCallback(0x5f8, callback);
-        }
-
-        public void RegisterClearCallback(MethodCallback callback)
-        {
-            RegisterCallback(0x674, callback);
-        }
-
-        public void RegisterReportCallback(MethodCallback callback)
-        {
-            RegisterCallback(0x6c3, callback);
-        }
-
-        public void RegisterUniformBufferUpdateCallback(MethodCallback callback)
-        {
-            for (int index = 0; index < 16; index++)
-            {
-                RegisterCallback(0x8e4 + index, callback);
-            }
-        }
-
-        public void RegisterUniformBufferBind0Callback(MethodCallback callback)
-        {
-            RegisterCallback(0x904, callback);
-        }
-
-        public void RegisterUniformBufferBind1Callback(MethodCallback callback)
-        {
-            RegisterCallback(0x90c, callback);
-        }
-
-        public void RegisterUniformBufferBind2Callback(MethodCallback callback)
-        {
-            RegisterCallback(0x914, callback);
-        }
-
-        public void RegisterUniformBufferBind3Callback(MethodCallback callback)
-        {
-            RegisterCallback(0x91c, callback);
-        }
-
-        public void RegisterUniformBufferBind4Callback(MethodCallback callback)
-        {
-            RegisterCallback(0x924, callback);
-        }
-
-        public CopyTexture GetCopyDstTexture()
-        {
-            return Get<CopyTexture>(MethodOffset.CopyDstTexture);
-        }
-
-        public CopyTexture GetCopySrcTexture()
-        {
-            return Get<CopyTexture>(MethodOffset.CopySrcTexture);
-        }
-
-        public RtColorState GetRtColorState(int index)
-        {
-            return Get<RtColorState>(MethodOffset.RtColorState + 16 * index);
-        }
-
-        public CopyTextureControl GetCopyTextureControl()
-        {
-            return Get<CopyTextureControl>(MethodOffset.CopyTextureControl);
-        }
-
-        public CopyRegion GetCopyRegion()
-        {
-            return Get<CopyRegion>(MethodOffset.CopyRegion);
-        }
-
-        public ViewportTransform GetViewportTransform(int index)
-        {
-            return Get<ViewportTransform>(MethodOffset.ViewportTransform + 8 * index);
-        }
-
-        public ViewportExtents GetViewportExtents(int index)
-        {
-            return Get<ViewportExtents>(MethodOffset.ViewportExtents + 4 * index);
-        }
-
-        public VertexBufferDrawState GetVertexBufferDrawState()
-        {
-            return Get<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState);
-        }
-
-        public ClearColors GetClearColors()
-        {
-            return Get<ClearColors>(MethodOffset.ClearColors);
-        }
-
-        public float GetClearDepthValue()
-        {
-            return Get<float>(MethodOffset.ClearDepthValue);
-        }
-
-        public int GetClearStencilValue()
-        {
-            return _backingMemory[(int)MethodOffset.ClearStencilValue];
-        }
-
-        public StencilBackMasks GetStencilBackMasks()
-        {
-            return Get<StencilBackMasks>(MethodOffset.StencilBackMasks);
-        }
-
-        public RtDepthStencilState GetRtDepthStencilState()
-        {
-            return Get<RtDepthStencilState>(MethodOffset.RtDepthStencilState);
-        }
-
-        public VertexAttribState GetVertexAttribState(int index)
-        {
-            return Get<VertexAttribState>(MethodOffset.VertexAttribState + index);
-        }
-
-        public Size3D GetRtDepthStencilSize()
-        {
-            return Get<Size3D>(MethodOffset.RtDepthStencilSize);
-        }
-
-        public Bool GetDepthTestEnable()
-        {
-            return Get<Bool>(MethodOffset.DepthTestEnable);
-        }
-
-        public CompareOp GetDepthTestFunc()
-        {
-            return Get<CompareOp>(MethodOffset.DepthTestFunc);
-        }
-
-        public Bool GetDepthWriteEnable()
-        {
-            return Get<Bool>(MethodOffset.DepthWriteEnable);
-        }
-
-        public Bool GetBlendEnable(int index)
-        {
-            return Get<Bool>(MethodOffset.BlendEnable + index);
-        }
-
-        public StencilTestState GetStencilTestState()
-        {
-            return Get<StencilTestState>(MethodOffset.StencilTestState);
-        }
-
-        public int GetBaseVertex()
-        {
-            return _backingMemory[(int)MethodOffset.FirstVertex];
-        }
-
-        public int GetBaseInstance()
-        {
-            return _backingMemory[(int)MethodOffset.FirstInstance];
-        }
-
-        public PoolState GetSamplerPoolState()
-        {
-            return Get<PoolState>(MethodOffset.SamplerPoolState);
-        }
-
-        public PoolState GetTexturePoolState()
-        {
-            return Get<PoolState>(MethodOffset.TexturePoolState);
-        }
-
-        public StencilBackTestState GetStencilBackTestState()
-        {
-            return Get<StencilBackTestState>(MethodOffset.StencilBackTestState);
-        }
-
-        public TextureMsaaMode GetRtMsaaMode()
-        {
-            return Get<TextureMsaaMode>(MethodOffset.RtMsaaMode);
-        }
-
-        public GpuVa GetShaderBaseAddress()
-        {
-            return Get<GpuVa>(MethodOffset.ShaderBaseAddress);
-        }
-
-        public PrimitiveRestartState GetPrimitiveRestartState()
-        {
-            return Get<PrimitiveRestartState>(MethodOffset.PrimitiveRestartState);
-        }
-
-        public IndexBufferState GetIndexBufferState()
-        {
-            return Get<IndexBufferState>(MethodOffset.IndexBufferState);
-        }
-
-        public FaceState GetFaceState()
-        {
-            return Get<FaceState>(MethodOffset.FaceState);
-        }
-
-        public ReportState GetReportState()
-        {
-            return Get<ReportState>(MethodOffset.ReportState);
-        }
-
-        public VertexBufferState GetVertexBufferState(int index)
-        {
-            return Get<VertexBufferState>(MethodOffset.VertexBufferState + 4 * index);
-        }
-
-        public BlendState GetBlendState(int index)
-        {
-            return Get<BlendState>(MethodOffset.BlendState + 8 * index);
-        }
-
-        public GpuVa GetVertexBufferEndAddress(int index)
-        {
-            return Get<GpuVa>(MethodOffset.VertexBufferEndAddress + 2 * index);
-        }
-
-        public ShaderState GetShaderState(int index)
-        {
-            return Get<ShaderState>(MethodOffset.ShaderState + 16 * index);
-        }
-
-        public UniformBufferState GetUniformBufferState()
-        {
-            return Get<UniformBufferState>(MethodOffset.UniformBufferState);
-        }
-
         public void SetUniformBufferOffset(int offset)
         {
             _backingMemory[(int)MethodOffset.UniformBufferState + 3] = offset;
         }
 
-        public int GetTextureBufferIndex()
-        {
-            return _backingMemory[(int)MethodOffset.TextureBufferIndex];
-        }
-
         private void InitializeDefaultState()
         {
             // Depth ranges.
@@ -341,80 +101,50 @@ namespace Ryujinx.Graphics.Gpu.State
             _backingMemory[(int)MethodOffset.RtColorMask] = 0x1111;
         }
 
-        private void InitializeStateWatchers()
+        public void RegisterCallback(MethodOffset offset, int count, MethodCallback callback)
         {
-            SetWriteStateFlag(MethodOffset.RtColorState, StateWriteFlags.RtColorState, 16 * 8);
-
-            SetWriteStateFlag(MethodOffset.ViewportTransform, StateWriteFlags.ViewportTransform, 8 * 8);
-            SetWriteStateFlag(MethodOffset.ViewportExtents,   StateWriteFlags.ViewportTransform, 4 * 8);
-
-            SetWriteStateFlag<VertexBufferDrawState>(MethodOffset.VertexBufferDrawState, StateWriteFlags.VertexBufferState);
-
-            SetWriteStateFlag<DepthBiasState>(MethodOffset.DepthBiasState, StateWriteFlags.DepthBiasState);
-
-            SetWriteStateFlag(MethodOffset.DepthBiasFactor, StateWriteFlags.DepthBiasState, 1);
-            SetWriteStateFlag(MethodOffset.DepthBiasUnits,  StateWriteFlags.DepthBiasState, 1);
-            SetWriteStateFlag(MethodOffset.DepthBiasClamp,  StateWriteFlags.DepthBiasState, 1);
-
-            SetWriteStateFlag<RtDepthStencilState>(MethodOffset.RtDepthStencilState, StateWriteFlags.RtDepthStencilState);
-            SetWriteStateFlag<Size3D>             (MethodOffset.RtDepthStencilSize,  StateWriteFlags.RtDepthStencilState);
-
-            SetWriteStateFlag(MethodOffset.DepthTestEnable,  StateWriteFlags.DepthTestState, 1);
-            SetWriteStateFlag(MethodOffset.DepthWriteEnable, StateWriteFlags.DepthTestState, 1);
-            SetWriteStateFlag(MethodOffset.DepthTestFunc,    StateWriteFlags.DepthTestState, 1);
-
-            SetWriteStateFlag(MethodOffset.VertexAttribState, StateWriteFlags.VertexAttribState, 16);
-
-            SetWriteStateFlag<StencilBackMasks>    (MethodOffset.StencilBackMasks,     StateWriteFlags.StencilTestState);
-            SetWriteStateFlag<StencilTestState>    (MethodOffset.StencilTestState,     StateWriteFlags.StencilTestState);
-            SetWriteStateFlag<StencilBackTestState>(MethodOffset.StencilBackTestState, StateWriteFlags.StencilTestState);
-
-            SetWriteStateFlag<PoolState>(MethodOffset.SamplerPoolState, StateWriteFlags.SamplerPoolState);
-            SetWriteStateFlag<PoolState>(MethodOffset.TexturePoolState, StateWriteFlags.TexturePoolState);
-
-            SetWriteStateFlag<ShaderState>(MethodOffset.ShaderBaseAddress, StateWriteFlags.ShaderState);
-
-            SetWriteStateFlag<PrimitiveRestartState>(MethodOffset.PrimitiveRestartState, StateWriteFlags.PrimitiveRestartState);
-
-            SetWriteStateFlag<IndexBufferState>(MethodOffset.IndexBufferState, StateWriteFlags.IndexBufferState);
-
-            SetWriteStateFlag<FaceState>(MethodOffset.FaceState, StateWriteFlags.FaceState);
-
-            SetWriteStateFlag<RtColorMask>(MethodOffset.RtColorMask, StateWriteFlags.RtColorMask);
-
-            SetWriteStateFlag(MethodOffset.VertexBufferInstanced,  StateWriteFlags.VertexBufferState, 16);
-            SetWriteStateFlag(MethodOffset.VertexBufferState,      StateWriteFlags.VertexBufferState, 4 * 16);
-            SetWriteStateFlag(MethodOffset.VertexBufferEndAddress, StateWriteFlags.VertexBufferState, 2 * 16);
-
-            SetWriteStateFlag(MethodOffset.BlendEnable, StateWriteFlags.BlendState, 8);
-            SetWriteStateFlag(MethodOffset.BlendState,  StateWriteFlags.BlendState, 8 * 8);
-
-            SetWriteStateFlag(MethodOffset.ShaderState, StateWriteFlags.ShaderState, 16 * 6);
-
-            SetWriteStateFlag(MethodOffset.TextureBufferIndex, StateWriteFlags.TexturePoolState, 1);
+            for (int index = 0; index < count; index++)
+            {
+                _registers[(int)offset + index].Callback = callback;
+            }
         }
 
-        private void SetWriteStateFlag<T>(MethodOffset offset, StateWriteFlags flag)
+        public void RegisterCallback(MethodOffset offset, MethodCallback callback)
         {
-            SetWriteStateFlag(offset, flag, Marshal.SizeOf<T>());
+            _registers[(int)offset].Callback = callback;
         }
 
-        private void SetWriteStateFlag(MethodOffset offset, StateWriteFlags flag, int size)
+        public bool QueryModified(params MethodOffset[] offsets)
         {
-            for (int index = 0; index < size; index++)
+            bool modified = false;
+
+            for (int index = 0; index < offsets.Length; index++)
             {
-                _registers[(int)offset + index].WriteFlag = flag;
+                modified |= QueryModified(offsets[index]);
             }
+
+            return modified;
         }
 
-        public void RegisterCallback(MethodOffset offset, MethodCallback callback)
+        public bool QueryModified(MethodOffset offset)
         {
-            _registers[(int)offset].Callback = callback;
+            bool modified = _registers[(int)offset].Modified;
+
+            _registers[(int)offset].Modified = false;
+
+            return modified;
         }
 
-        private void RegisterCallback(int offset, MethodCallback callback)
+        public T Get<T>(MethodOffset offset, int index) where T : struct
         {
-            _registers[offset].Callback = callback;
+            Register register = _registers[(int)offset];
+
+            if ((uint)index >= register.Count)
+            {
+                throw new ArgumentOutOfRangeException(nameof(index));
+            }
+
+            return Get<T>(offset + index * register.Stride);
         }
 
         public T Get<T>(MethodOffset offset) where T : struct

+ 56 - 0
Ryujinx.Graphics.Gpu/State/GpuStateTable.cs

@@ -0,0 +1,56 @@
+using System;
+using System.Diagnostics;
+using System.Runtime.InteropServices;
+
+namespace Ryujinx.Graphics.Gpu.State
+{
+    static class GpuStateTable
+    {
+        public struct TableItem
+        {
+            public MethodOffset Offset { get; }
+
+            public int Size  { get; }
+            public int Count { get; }
+
+            public TableItem(MethodOffset offset, Type type, int count)
+            {
+                int sizeInBytes = Marshal.SizeOf(type);
+
+                Debug.Assert((sizeInBytes & 3) == 0);
+
+                Offset = offset;
+                Size   = sizeInBytes / 4;
+                Count  = count;
+            }
+        }
+
+        public static TableItem[] Table = new TableItem[]
+        {
+            new TableItem(MethodOffset.RtColorState,           typeof(RtColorState),          8),
+            new TableItem(MethodOffset.ViewportTransform,      typeof(ViewportTransform),     8),
+            new TableItem(MethodOffset.ViewportExtents,        typeof(ViewportExtents),       8),
+            new TableItem(MethodOffset.VertexBufferDrawState,  typeof(VertexBufferDrawState), 1),
+            new TableItem(MethodOffset.DepthBiasState,         typeof(DepthBiasState),        1),
+            new TableItem(MethodOffset.StencilBackMasks,       typeof(StencilBackMasks),      1),
+            new TableItem(MethodOffset.RtDepthStencilState,    typeof(RtDepthStencilState),   1),
+            new TableItem(MethodOffset.VertexAttribState,      typeof(VertexAttribState),     16),
+            new TableItem(MethodOffset.RtDepthStencilSize,     typeof(Size3D),                1),
+            new TableItem(MethodOffset.BlendEnable,            typeof(Boolean32),             8),
+            new TableItem(MethodOffset.StencilTestState,       typeof(StencilTestState),      1),
+            new TableItem(MethodOffset.SamplerPoolState,       typeof(PoolState),             1),
+            new TableItem(MethodOffset.TexturePoolState,       typeof(PoolState),             1),
+            new TableItem(MethodOffset.StencilBackTestState,   typeof(StencilBackTestState),  1),
+            new TableItem(MethodOffset.ShaderBaseAddress,      typeof(GpuVa),                 1),
+            new TableItem(MethodOffset.PrimitiveRestartState,  typeof(PrimitiveRestartState), 1),
+            new TableItem(MethodOffset.IndexBufferState,       typeof(IndexBufferState),      1),
+            new TableItem(MethodOffset.VertexBufferInstanced,  typeof(Boolean32),             16),
+            new TableItem(MethodOffset.FaceState,              typeof(FaceState),             1),
+            new TableItem(MethodOffset.RtColorMask,            typeof(RtColorMask),           8),
+            new TableItem(MethodOffset.VertexBufferState,      typeof(VertexBufferState),     16),
+            new TableItem(MethodOffset.BlendState,             typeof(BlendState),            8),
+            new TableItem(MethodOffset.VertexBufferEndAddress, typeof(GpuVa),                 16),
+            new TableItem(MethodOffset.ShaderState,            typeof(ShaderState),           6),
+        };
+    }
+}

+ 0 - 5
Ryujinx.Graphics.Gpu/State/GpuVa.cs

@@ -9,10 +9,5 @@ namespace Ryujinx.Graphics.Gpu.State
         {
             return Low | ((ulong)High << 32);
         }
-
-        public bool IsNullPtr()
-        {
-            return (Low | High) == 0;
-        }
     }
 }

+ 71 - 58
Ryujinx.Graphics.Gpu/State/MethodOffset.cs

@@ -2,63 +2,76 @@ namespace Ryujinx.Graphics.Gpu.State
 {
     enum MethodOffset
     {
-        Inline2MemoryParams    = 0x60,
-        Inline2MemoryExecute   = 0x6c,
-        Inline2MemoryPushData  = 0x6d,
-        CopyDstTexture         = 0x80,
-        CopySrcTexture         = 0x8c,
-        DispatchParamsAddress  = 0xad,
-        Dispatch               = 0xaf,
-        CopyBufferParams       = 0x100,
-        CopyBufferSwizzle      = 0x1c2,
-        CopyBufferDstTexture   = 0x1c3,
-        CopyBufferSrcTexture   = 0x1ca,
-        RtColorState           = 0x200,
-        CopyTextureControl     = 0x223,
-        CopyRegion             = 0x22c,
-        ViewportTransform      = 0x280,
-        ViewportExtents        = 0x300,
-        VertexBufferDrawState  = 0x35d,
-        ClearColors            = 0x360,
-        ClearDepthValue        = 0x364,
-        ClearStencilValue      = 0x368,
-        DepthBiasState         = 0x370,
-        TextureBarrier         = 0x378,
-        StencilBackMasks       = 0x3d5,
-        InvalidateTextures     = 0x3dd,
-        TextureBarrierTiled    = 0x3df,
-        RtDepthStencilState    = 0x3f8,
-        VertexAttribState      = 0x458,
-        RtDepthStencilSize     = 0x48a,
-        DepthTestEnable        = 0x4b3,
-        DepthWriteEnable       = 0x4ba,
-        DepthTestFunc          = 0x4c3,
-        BlendEnable            = 0x4d8,
-        StencilTestState       = 0x4e0,
-        FirstVertex            = 0x50d,
-        FirstInstance          = 0x50e,
-        ResetCounter           = 0x54c,
-        RtDepthStencilEnable   = 0x54e,
-        ConditionState         = 0x554,
-        SamplerPoolState       = 0x557,
-        DepthBiasFactor        = 0x55b,
-        TexturePoolState       = 0x55d,
-        StencilBackTestState   = 0x565,
-        DepthBiasUnits         = 0x56f,
-        RtMsaaMode             = 0x574,
-        ShaderBaseAddress      = 0x582,
-        PrimitiveRestartState  = 0x591,
-        IndexBufferState       = 0x5f2,
-        DepthBiasClamp         = 0x61f,
-        VertexBufferInstanced  = 0x620,
-        FaceState              = 0x646,
-        RtColorMask            = 0x680,
-        ReportState            = 0x6c0,
-        VertexBufferState      = 0x700,
-        BlendState             = 0x780,
-        VertexBufferEndAddress = 0x7c0,
-        ShaderState            = 0x800,
-        UniformBufferState     = 0x8e0,
-        TextureBufferIndex     = 0x982
+        I2mParams                       = 0x60,
+        LaunchDma                       = 0x6c,
+        LoadInlineData                  = 0x6d,
+        CopyDstTexture                  = 0x80,
+        CopySrcTexture                  = 0x8c,
+        DispatchParamsAddress           = 0xad,
+        Dispatch                        = 0xaf,
+        CopyBuffer                      = 0xc0,
+        CopyBufferParams                = 0x100,
+        CopyBufferSwizzle               = 0x1c2,
+        CopyBufferDstTexture            = 0x1c3,
+        CopyBufferSrcTexture            = 0x1ca,
+        RtColorState                    = 0x200,
+        CopyTextureControl              = 0x223,
+        CopyRegion                      = 0x22c,
+        CopyTexture                     = 0x237,
+        ViewportTransform               = 0x280,
+        ViewportExtents                 = 0x300,
+        VertexBufferDrawState           = 0x35d,
+        ClearColors                     = 0x360,
+        ClearDepthValue                 = 0x364,
+        ClearStencilValue               = 0x368,
+        DepthBiasState                  = 0x370,
+        TextureBarrier                  = 0x378,
+        StencilBackMasks                = 0x3d5,
+        InvalidateTextures              = 0x3dd,
+        TextureBarrierTiled             = 0x3df,
+        RtDepthStencilState             = 0x3f8,
+        VertexAttribState               = 0x458,
+        RtDepthStencilSize              = 0x48a,
+        DepthTestEnable                 = 0x4b3,
+        DepthWriteEnable                = 0x4ba,
+        DepthTestFunc                   = 0x4c3,
+        BlendEnable                     = 0x4d8,
+        StencilTestState                = 0x4e0,
+        FirstVertex                     = 0x50d,
+        FirstInstance                   = 0x50e,
+        ResetCounter                    = 0x54c,
+        RtDepthStencilEnable            = 0x54e,
+        ConditionState                  = 0x554,
+        SamplerPoolState                = 0x557,
+        DepthBiasFactor                 = 0x55b,
+        TexturePoolState                = 0x55d,
+        StencilBackTestState            = 0x565,
+        DepthBiasUnits                  = 0x56f,
+        RtMsaaMode                      = 0x574,
+        ShaderBaseAddress               = 0x582,
+        DrawEnd                         = 0x585,
+        DrawBegin                       = 0x586,
+        PrimitiveRestartState           = 0x591,
+        IndexBufferState                = 0x5f2,
+        IndexBufferCount                = 0x5f8,
+        DepthBiasClamp                  = 0x61f,
+        VertexBufferInstanced           = 0x620,
+        FaceState                       = 0x646,
+        Clear                           = 0x674,
+        RtColorMask                     = 0x680,
+        ReportState                     = 0x6c0,
+        Report                          = 0x6c3,
+        VertexBufferState               = 0x700,
+        BlendState                      = 0x780,
+        VertexBufferEndAddress          = 0x7c0,
+        ShaderState                     = 0x800,
+        UniformBufferState              = 0x8e0,
+        UniformBufferUpdateData         = 0x8e4,
+        UniformBufferBindVertex         = 0x904,
+        UniformBufferBindTessControl    = 0x90c,
+        UniformBufferBindTessEvaluation = 0x914,
+        UniformBufferBindGeometry       = 0x91c,
+        UniformBufferBindFragment       = 0x924,
+        TextureBufferIndex              = 0x982
     }
 }

+ 2 - 2
Ryujinx.Graphics.Gpu/State/PrimitiveRestartState.cs

@@ -2,7 +2,7 @@ namespace Ryujinx.Graphics.Gpu.State
 {
     struct PrimitiveRestartState
     {
-        public bool Enable;
-        public int  Index;
+        public Boolean32 Enable;
+        public int       Index;
     }
 }

+ 8 - 0
Ryujinx.Graphics.Gpu/State/RtColorState.cs

@@ -9,5 +9,13 @@ namespace Ryujinx.Graphics.Gpu.State
         public MemoryLayout MemoryLayout;
         public int          Depth;
         public int          LayerSize;
+        public int          BaseLayer;
+        public int          Unknown0x24;
+        public int          Padding0;
+        public int          Padding1;
+        public int          Padding2;
+        public int          Padding3;
+        public int          Padding4;
+        public int          Padding5;
     }
 }

+ 4 - 0
Ryujinx.Graphics.Gpu/State/RtFormat.cs

@@ -8,6 +8,8 @@ namespace Ryujinx.Graphics.Gpu.State
         D32Float          = 0xa,
         D16Unorm          = 0x13,
         D24UnormS8Uint    = 0x14,
+        D24Unorm          = 0x15,
+        S8UintD24Unorm    = 0x16,
         S8Uint            = 0x17,
         D32FloatS8Uint    = 0x19,
         R32G32B32A32Float = 0xc0,
@@ -74,6 +76,8 @@ namespace Ryujinx.Graphics.Gpu.State
                 case RtFormat.D32Float:             return new FormatInfo(Format.D32Float,          1, 1, 4);
                 case RtFormat.D16Unorm:             return new FormatInfo(Format.D16Unorm,          1, 1, 2);
                 case RtFormat.D24UnormS8Uint:       return new FormatInfo(Format.D24UnormS8Uint,    1, 1, 4);
+                case RtFormat.D24Unorm:             return new FormatInfo(Format.D24UnormS8Uint,    1, 1, 4);
+                case RtFormat.S8UintD24Unorm:       return new FormatInfo(Format.D24UnormS8Uint,    1, 1, 4);
                 case RtFormat.S8Uint:               return new FormatInfo(Format.S8Uint,            1, 1, 1);
                 case RtFormat.D32FloatS8Uint:       return new FormatInfo(Format.D32FloatS8Uint,    1, 1, 8);
                 case RtFormat.R32G32B32A32Float:    return new FormatInfo(Format.R32G32B32A32Float, 1, 1, 16);

+ 8 - 0
Ryujinx.Graphics.Gpu/State/ShaderState.cs

@@ -10,6 +10,14 @@ namespace Ryujinx.Graphics.Gpu.State
         public uint       Unknown0x14;
         public uint       Unknown0x18;
         public uint       Unknown0x1c;
+        public uint       Unknown0x20;
+        public uint       Unknown0x24;
+        public uint       Unknown0x28;
+        public uint       Unknown0x2c;
+        public uint       Unknown0x30;
+        public uint       Unknown0x34;
+        public uint       Unknown0x38;
+        public uint       Unknown0x3c;
 
         public bool UnpackEnable()
         {

+ 1 - 1
Ryujinx.Graphics.Gpu/State/StencilBackTestState.cs

@@ -5,7 +5,7 @@ namespace Ryujinx.Graphics.Gpu.State
 {
     struct StencilBackTestState
     {
-        public Bool      TwoSided;
+        public Boolean32 TwoSided;
         public StencilOp BackSFail;
         public StencilOp BackDpFail;
         public StencilOp BackDpPass;

+ 1 - 1
Ryujinx.Graphics.Gpu/State/StencilTestState.cs

@@ -5,7 +5,7 @@ namespace Ryujinx.Graphics.Gpu.State
 {
     struct StencilTestState
     {
-        public Bool      Enable;
+        public Boolean32 Enable;
         public StencilOp FrontSFail;
         public StencilOp FrontDpFail;
         public StencilOp FrontDpPass;

+ 9 - 6
Ryujinx.Graphics.OpenGL/Pipeline.cs

@@ -906,12 +906,15 @@ namespace Ryujinx.Graphics.OpenGL
 
         private void RestoreComponentMask(int index)
         {
-            GL.ColorMask(
-                index,
-                (_componentMasks[index] & 1u) != 0,
-                (_componentMasks[index] & 2u) != 0,
-                (_componentMasks[index] & 4u) != 0,
-                (_componentMasks[index] & 8u) != 0);
+            if (_componentMasks != null)
+            {
+                GL.ColorMask(
+                    index,
+                    (_componentMasks[index] & 1u) != 0,
+                    (_componentMasks[index] & 2u) != 0,
+                    (_componentMasks[index] & 4u) != 0,
+                    (_componentMasks[index] & 8u) != 0);
+            }
         }
 
         public void RebindProgram()

+ 0 - 1
Ryujinx.Graphics.Shader/Decoders/ImageComponents.cs

@@ -6,6 +6,5 @@ namespace Ryujinx.Graphics.Shader.Decoders
         Green = 1 << 1,
         Blue  = 1 << 2,
         Alpha = 1 << 3
-
     }
 }

+ 1 - 0
Ryujinx.Graphics.Shader/Decoders/SystemRegister.cs

@@ -2,6 +2,7 @@ namespace Ryujinx.Graphics.Shader.Decoders
 {
     enum SystemRegister
     {
+        ThreadId  = 0x20,
         ThreadIdX = 0x21,
         ThreadIdY = 0x22,
         ThreadIdZ = 0x23,

+ 14 - 0
Ryujinx.Graphics.Shader/Instructions/InstEmitMove.cs

@@ -27,6 +27,20 @@ namespace Ryujinx.Graphics.Shader.Instructions
 
             switch (sysReg)
             {
+                case SystemRegister.ThreadId:
+                {
+                    Operand tidX = Attribute(AttributeConsts.ThreadIdX);
+                    Operand tidY = Attribute(AttributeConsts.ThreadIdY);
+                    Operand tidZ = Attribute(AttributeConsts.ThreadIdZ);
+
+                    tidY = context.ShiftLeft(tidY, Const(16));
+                    tidZ = context.ShiftLeft(tidZ, Const(26));
+
+                    src = context.BitwiseOr(tidX, context.BitwiseOr(tidY, tidZ));
+
+                    break;
+                }
+
                 case SystemRegister.ThreadIdX: src = Attribute(AttributeConsts.ThreadIdX); break;
                 case SystemRegister.ThreadIdY: src = Attribute(AttributeConsts.ThreadIdY); break;
                 case SystemRegister.ThreadIdZ: src = Attribute(AttributeConsts.ThreadIdZ); break;

+ 7 - 1
Ryujinx.Graphics.Shader/StructuredIr/InstructionInfo.cs

@@ -59,6 +59,8 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
             Add(Instruction.ExponentB2,               VariableType.Scalar, VariableType.Scalar);
             Add(Instruction.Floor,                    VariableType.F32,    VariableType.F32);
             Add(Instruction.FusedMultiplyAdd,         VariableType.F32,    VariableType.F32,    VariableType.F32,    VariableType.F32);
+            Add(Instruction.ImageLoad,                VariableType.F32);
+            Add(Instruction.ImageStore,               VariableType.None);
             Add(Instruction.IsNan,                    VariableType.Bool,   VariableType.F32);
             Add(Instruction.LoadAttribute,            VariableType.F32,    VariableType.S32,    VariableType.S32);
             Add(Instruction.LoadConstant,             VariableType.F32,    VariableType.S32,    VariableType.S32);
@@ -105,7 +107,11 @@ namespace Ryujinx.Graphics.Shader.StructuredIr
 
         public static VariableType GetSrcVarType(Instruction inst, int index)
         {
-            if (inst == Instruction.TextureSample)
+            // TODO: Return correct type depending on source index,
+            // that can improve the decompiler output.
+            if (inst == Instruction.TextureSample ||
+                inst == Instruction.ImageLoad     ||
+                inst == Instruction.ImageStore)
             {
                 return VariableType.F32;
             }

+ 2 - 2
Ryujinx.HLE/HOS/Services/Nv/NvDrvServices/NvHostAsGpu/Types/AddressSpaceContext.cs

@@ -59,9 +59,9 @@ namespace Ryujinx.HLE.HOS.Services.Nv.NvDrvServices.NvHostAsGpu.Types
                 _cpuMemory.WriteBytes((long)address, data.ToArray());
             }
 
-            public (ulong, ulong)[] GetModifiedRanges(ulong address, ulong size)
+            public (ulong, ulong)[] GetModifiedRanges(ulong address, ulong size, ResourceName name)
             {
-                return _cpuMemory.GetModifiedRanges(address, size);
+                return _cpuMemory.GetModifiedRanges(address, size, (int)name);
             }
 
             public int GetPageSize()