diff --git a/Ryujinx.Graphics.Gpu/Engine/Compute.cs b/Ryujinx.Graphics.Gpu/Engine/Compute.cs
index c7e059ba3a..bcff595343 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Compute.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Compute.cs
@@ -141,8 +141,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
 
             TextureManager.SetComputeImages(imageBindings);
 
-            BufferManager.CommitComputeBindings();
             TextureManager.CommitComputeBindings();
+            BufferManager.CommitComputeBindings();
 
             _context.Renderer.Pipeline.DispatchCompute(
                 qmd.CtaRasterWidth,
diff --git a/Ryujinx.Graphics.Gpu/Engine/Methods.cs b/Ryujinx.Graphics.Gpu/Engine/Methods.cs
index 0731f1c2bb..033311b2b0 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Methods.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Methods.cs
@@ -304,8 +304,8 @@ namespace Ryujinx.Graphics.Gpu.Engine
         {
             UpdateStorageBuffers();
 
-            BufferManager.CommitGraphicsBindings();
             TextureManager.CommitGraphicsBindings();
+            BufferManager.CommitGraphicsBindings();
         }
 
         /// <summary>
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
index 173340b3ba..7fea7ebe0c 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureBindingsManager.cs
@@ -303,7 +303,7 @@ namespace Ryujinx.Graphics.Gpu.Image
                     // Ensure that the buffer texture is using the correct buffer as storage.
                     // Buffers are frequently re-created to accomodate larger data, so we need to re-bind
                     // to ensure we're not using a old buffer that was already deleted.
-                    _context.Methods.BufferManager.SetBufferTextureStorage(hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, _isCompute);
+                    _context.Methods.BufferManager.SetBufferTextureStorage(hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, bindingInfo.Format, false);
                 }
 
                 Sampler sampler = _samplerPool.Get(samplerId);
@@ -349,12 +349,26 @@ namespace Ryujinx.Graphics.Gpu.Image
 
                 ITexture hostTexture = texture?.GetTargetTexture(bindingInfo.Target);
 
+                bool isStore = bindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore);
+
                 if (hostTexture != null && texture.Target == Target.TextureBuffer)
                 {
                     // Ensure that the buffer texture is using the correct buffer as storage.
                     // Buffers are frequently re-created to accomodate larger data, so we need to re-bind
                     // to ensure we're not using a old buffer that was already deleted.
-                    _context.Methods.BufferManager.SetBufferTextureStorage(hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, _isCompute);
+
+                    Format format = bindingInfo.Format;
+
+                    if (format == 0 && texture != null)
+                    {
+                        format = texture.Format;
+                    }
+
+                    _context.Methods.BufferManager.SetBufferTextureStorage(hostTexture, texture.Range.GetSubRange(0).Address, texture.Size, bindingInfo, format, true);
+                } 
+                else if (isStore)
+                {
+                    texture?.SignalModified();
                 }
 
                 if (_imageState[stageIndex][index].Texture != hostTexture || _rebind)
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs b/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs
index e85df136be..62862e7413 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureDescriptor.cs
@@ -153,6 +153,15 @@ namespace Ryujinx.Graphics.Gpu.Image
             return (int)(Word4 & 0xffff) + 1;
         }
 
+        /// <summary>
+        /// Unpack the width of a buffer texture.
+        /// </summary>
+        /// <returns>The texture width</returns>
+        public int UnpackBufferTextureWidth()
+        {
+            return (int)((Word4 & 0xffff) | (Word3 << 16)) + 1;
+        }
+
         /// <summary>
         /// Unpacks the texture sRGB format flag.
         /// </summary>
diff --git a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
index eece2a79ec..8f225f1634 100644
--- a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
@@ -172,8 +172,6 @@ namespace Ryujinx.Graphics.Gpu.Image
         /// <returns>The texture information</returns>
         private TextureInfo GetInfo(TextureDescriptor descriptor, out int layerSize)
         {
-            int width         = descriptor.UnpackWidth();
-            int height        = descriptor.UnpackHeight();
             int depthOrLayers = descriptor.UnpackDepth();
             int levels        = descriptor.UnpackLevels();
 
@@ -190,6 +188,9 @@ namespace Ryujinx.Graphics.Gpu.Image
 
             Target target = descriptor.UnpackTextureTarget().Convert((samplesInX | samplesInY) != 1);
 
+            int width = target == Target.TextureBuffer ? descriptor.UnpackBufferTextureWidth() : descriptor.UnpackWidth();
+            int height = descriptor.UnpackHeight();
+
             // We use 2D targets for 1D textures as that makes texture cache
             // management easier. We don't know the target for render target
             // and copies, so those would normally use 2D targets, which are
diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
index 08d52faa4b..b2cd1ced70 100644
--- a/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
+++ b/Ryujinx.Graphics.Gpu/Memory/BufferManager.cs
@@ -1,9 +1,11 @@
 using Ryujinx.Common;
 using Ryujinx.Graphics.GAL;
+using Ryujinx.Graphics.Gpu.Image;
 using Ryujinx.Graphics.Gpu.State;
 using Ryujinx.Graphics.Shader;
 using Ryujinx.Memory.Range;
 using System;
+using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Linq;
 
@@ -31,6 +33,7 @@ namespace Ryujinx.Graphics.Gpu.Memory
         private IndexBuffer _indexBuffer;
         private VertexBuffer[] _vertexBuffers;
         private BufferBounds[] _transformFeedbackBuffers;
+        private List<BufferTextureBinding> _bufferTextures;
 
         /// <summary>
         /// Holds shader stage buffer state and binding information.
@@ -138,6 +141,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
                 _gpStorageBuffers[index] = new BuffersPerStage(Constants.TotalGpStorageBuffers);
                 _gpUniformBuffers[index] = new BuffersPerStage(Constants.TotalGpUniformBuffers);
             }
+
+            _bufferTextures = new List<BufferTextureBinding>();
         }
 
         /// <summary>
@@ -620,10 +625,39 @@ namespace Ryujinx.Graphics.Gpu.Memory
 
             _context.Renderer.Pipeline.SetUniformBuffers(uRanges);
 
+            CommitBufferTextureBindings();
+
             // Force rebind after doing compute work.
             _rebind = true;
         }
 
+        /// <summary>
+        /// Commit any queued buffer texture bindings.
+        /// </summary>
+        private void CommitBufferTextureBindings()
+        {
+            if (_bufferTextures.Count > 0)
+            {
+                foreach (var binding in _bufferTextures)
+                {
+                    binding.Texture.SetStorage(GetBufferRange(binding.Address, binding.Size, binding.BindingInfo.Flags.HasFlag(TextureUsageFlags.ImageStore)));
+
+                    // The texture must be rebound to use the new storage if it was updated.
+
+                    if (binding.IsImage)
+                    {
+                        _context.Renderer.Pipeline.SetImage(binding.BindingInfo.Binding, binding.Texture, binding.Format);
+                    }
+                    else
+                    {
+                        _context.Renderer.Pipeline.SetTexture(binding.BindingInfo.Binding, binding.Texture);
+                    }
+                }
+
+                _bufferTextures.Clear();
+            }
+        }
+
         /// <summary>
         /// Ensures that the graphics engine bindings are visible to the host GPU.
         /// Note: this actually performs the binding using the host graphics API.
@@ -743,6 +777,8 @@ namespace Ryujinx.Graphics.Gpu.Memory
                 UpdateBuffers(_gpUniformBuffers);
             }
 
+            CommitBufferTextureBindings();
+
             _rebind = false;
         }
 
@@ -813,31 +849,19 @@ namespace Ryujinx.Graphics.Gpu.Memory
         }
 
         /// <summary>
-        /// Sets the buffer storage of a buffer texture.
+        /// Sets the buffer storage of a buffer texture. This will be bound when the buffer manager commits bindings.
         /// </summary>
         /// <param name="texture">Buffer texture</param>
         /// <param name="address">Address of the buffer in memory</param>
         /// <param name="size">Size of the buffer in bytes</param>
-        /// <param name="compute">Indicates if the buffer texture belongs to the compute or graphics pipeline</param>
-        public void SetBufferTextureStorage(ITexture texture, ulong address, ulong size, bool compute)
+        /// <param name="bindingInfo">Binding info for the buffer texture</param>
+        /// <param name="format">Format of the buffer texture</param>
+        /// <param name="isImage">Whether the binding is for an image or a sampler</param>
+        public void SetBufferTextureStorage(ITexture texture, ulong address, ulong size, TextureBindingInfo bindingInfo, Format format, bool isImage)
         {
             CreateBuffer(address, size);
 
-            if (_rebind)
-            {
-                // We probably had to modify existing buffers to create the texture buffer,
-                // so rebind everything to ensure we're using the new buffers for all bound resources.
-                if (compute)
-                {
-                    CommitComputeBindings();
-                }
-                else
-                {
-                    CommitGraphicsBindings();
-                }
-            }
-
-            texture.SetStorage(GetBufferRange(address, size));
+            _bufferTextures.Add(new BufferTextureBinding(texture, address, size, bindingInfo, format, isImage));
         }
 
         /// <summary>
diff --git a/Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs b/Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs
new file mode 100644
index 0000000000..cf0d225e87
--- /dev/null
+++ b/Ryujinx.Graphics.Gpu/Memory/BufferTextureBinding.cs
@@ -0,0 +1,60 @@
+using Ryujinx.Graphics.GAL;
+using Ryujinx.Graphics.Gpu.Image;
+
+namespace Ryujinx.Graphics.Gpu.Memory
+{
+    /// <summary>
+    /// A buffer binding to apply to a buffer texture.
+    /// </summary>
+    struct BufferTextureBinding
+    {
+        /// <summary>
+        /// The buffer texture.
+        /// </summary>
+        public ITexture Texture { get; }
+
+        /// <summary>
+        /// The base address of the buffer binding.
+        /// </summary>
+        public ulong Address { get; }
+
+        /// <summary>
+        /// The size of the buffer binding in bytes.
+        /// </summary>
+        public ulong Size { get; }
+
+        /// <summary>
+        /// The image or sampler binding info for the buffer texture.
+        /// </summary>
+        public TextureBindingInfo BindingInfo { get; }
+
+        /// <summary>
+        /// The image format for the binding.
+        /// </summary>
+        public Format Format { get; }
+
+        /// <summary>
+        /// Whether the binding is for an image or a sampler.
+        /// </summary>
+        public bool IsImage { get; }
+
+        /// <summary>
+        /// Create a new buffer texture binding.
+        /// </summary>
+        /// <param name="texture">Buffer texture</param>
+        /// <param name="address">Base address</param>
+        /// <param name="size">Size in bytes</param>
+        /// <param name="bindingInfo">Binding info</param>
+        /// <param name="format">Binding format</param>
+        /// <param name="isImage">Whether the binding is for an image or a sampler</param>
+        public BufferTextureBinding(ITexture texture, ulong address, ulong size, TextureBindingInfo bindingInfo, Format format, bool isImage)
+        {
+            Texture = texture;
+            Address = address;
+            Size = size;
+            BindingInfo = bindingInfo;
+            Format = format;
+            IsImage = isImage;
+        }
+    }
+}
diff --git a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
index bf89f29d6f..768a58e7bd 100644
--- a/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
+++ b/Ryujinx.Graphics.Gpu/Shader/ShaderCache.cs
@@ -35,7 +35,7 @@ namespace Ryujinx.Graphics.Gpu.Shader
         /// <summary>
         /// Version of the codegen (to be changed when codegen or guest format change).
         /// </summary>
-        private const ulong ShaderCodeGenVersion = 1961;
+        private const ulong ShaderCodeGenVersion = 2088;
 
         // Progress reporting helpers
         private int _shaderCount;
diff --git a/Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs b/Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs
index 5607fb401b..f49a064786 100644
--- a/Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs
+++ b/Ryujinx.Graphics.OpenGL/Image/TextureBuffer.cs
@@ -6,12 +6,17 @@ namespace Ryujinx.Graphics.OpenGL.Image
 {
     class TextureBuffer : TextureBase, ITexture
     {
+        private Renderer _renderer;
         private int _bufferOffset;
         private int _bufferSize;
+        private int _bufferCount;
 
         private BufferHandle _buffer;
 
-        public TextureBuffer(TextureCreateInfo info) : base(info) {}
+        public TextureBuffer(Renderer renderer, TextureCreateInfo info) : base(info)
+        {
+            _renderer = renderer;
+        }
 
         public void CopyTo(ITexture destination, int firstLayer, int firstLevel)
         {
@@ -50,16 +55,19 @@ namespace Ryujinx.Graphics.OpenGL.Image
 
         public void SetStorage(BufferRange buffer)
         {
-            if (buffer.Handle == _buffer &&
+            if (_buffer != BufferHandle.Null &&
                 buffer.Offset == _bufferOffset &&
-                buffer.Size == _bufferSize)
+                buffer.Size == _bufferSize &&
+                _renderer.BufferCount == _bufferCount)
             {
+                // Only rebind the buffer when more have been created.
                 return;
             }
 
             _buffer = buffer.Handle;
             _bufferOffset = buffer.Offset;
             _bufferSize = buffer.Size;
+            _bufferCount = _renderer.BufferCount;
 
             Bind(0);
 
diff --git a/Ryujinx.Graphics.OpenGL/Renderer.cs b/Ryujinx.Graphics.OpenGL/Renderer.cs
index 4a3f51bfd3..c3d083099a 100644
--- a/Ryujinx.Graphics.OpenGL/Renderer.cs
+++ b/Ryujinx.Graphics.OpenGL/Renderer.cs
@@ -30,6 +30,8 @@ namespace Ryujinx.Graphics.OpenGL
 
         internal ResourcePool ResourcePool { get; }
 
+        internal int BufferCount { get; private set; }
+
         public string GpuVendor { get; private set; }
         public string GpuRenderer { get; private set; }
         public string GpuVersion { get; private set; }
@@ -52,6 +54,8 @@ namespace Ryujinx.Graphics.OpenGL
 
         public BufferHandle CreateBuffer(int size)
         {
+            BufferCount++;
+
             return Buffer.Create(size);
         }
 
@@ -69,7 +73,7 @@ namespace Ryujinx.Graphics.OpenGL
         {
             if (info.Target == Target.TextureBuffer)
             {
-                return new TextureBuffer(info);
+                return new TextureBuffer(this, info);
             }
             else
             {
diff --git a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
index 3bfc064752..fc5b06b1aa 100644
--- a/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
+++ b/Ryujinx.Graphics.Shader/CodeGen/Glsl/Instructions/InstGenMemory.cs
@@ -111,6 +111,9 @@ namespace Ryujinx.Graphics.Shader.CodeGen.Glsl.Instructions
 
             if (texOp.Inst == Instruction.ImageStore)
             {
+                int texIndex = context.FindImageDescriptorIndex(texOp);
+                context.ImageDescriptors[texIndex] = context.ImageDescriptors[texIndex].SetFlag(TextureUsageFlags.ImageStore);
+
                 VariableType type = texOp.Format.GetComponentType();
 
                 string[] cElems = new string[4];
diff --git a/Ryujinx.Graphics.Shader/TextureUsageFlags.cs b/Ryujinx.Graphics.Shader/TextureUsageFlags.cs
index 1f02430987..87be0d0114 100644
--- a/Ryujinx.Graphics.Shader/TextureUsageFlags.cs
+++ b/Ryujinx.Graphics.Shader/TextureUsageFlags.cs
@@ -12,6 +12,7 @@ namespace Ryujinx.Graphics.Shader
 
         // Integer sampled textures must be noted for resolution scaling.
         ResScaleUnsupported = 1 << 0,
-        NeedsScaleValue = 1 << 1
+        NeedsScaleValue = 1 << 1,
+        ImageStore = 1 << 2
     }
 }