diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 97c55f2ecb56ee20be595e011c95dd634a27a879..c9f3a35e65abc2a81e02fce78886d7b23a4b5b67 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -422,7 +422,7 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers(
     }
     current_framebuffer_config_state = fb_config_state;
 
-    texture_cache.Guard(true);
+    texture_cache.GuardRenderTargets(true);
 
     View depth_surface{};
     if (using_depth_fb) {
@@ -500,7 +500,7 @@ std::pair<bool, bool> RasterizerOpenGL::ConfigureFramebuffers(
                                depth_surface->GetSurfaceParams().type == SurfaceType::DepthStencil;
     }
 
-    texture_cache.Guard(false);
+    texture_cache.GuardRenderTargets(false);
 
     current_state.draw.draw_framebuffer = framebuffer_cache.GetFramebuffer(fbkey);
     SyncViewport(current_state);
@@ -651,7 +651,9 @@ void RasterizerOpenGL::DrawArrays() {
     SetupVertexBuffer(vao);
 
     DrawParameters params = SetupDraw();
+    texture_cache.GuardSamplers(true);
     SetupShaders(params.primitive_mode);
+    texture_cache.GuardSamplers(false);
 
     ConfigureFramebuffers(state);
 
@@ -660,6 +662,10 @@ void RasterizerOpenGL::DrawArrays() {
     shader_program_manager->ApplyTo(state);
     state.Apply();
 
+    if (texture_cache.TextureBarrier()) {
+        glTextureBarrier();
+    }
+
     params.DispatchDraw();
 
     accelerate_draw = AccelDraw::Disabled;
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index a9e61cba13910a6f598381753b205f29489ee27c..353fa4e31b877a00d804366d87423a22df1a527e 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -70,8 +70,12 @@ public:
      * `Guard` guarantees that rendertargets don't unregister themselves if the
      * collide. Protection is currently only done on 3D slices.
      **/
-    void Guard(bool new_guard) {
-        guard_cache = new_guard;
+    void GuardRenderTargets(bool new_guard) {
+        guard_render_targets = new_guard;
+    }
+
+    void GuardSamplers(bool new_guard) {
+        guard_samplers = new_guard;
     }
 
     void FlushRegion(CacheAddr addr, std::size_t size) {
@@ -98,7 +102,25 @@ public:
             return {};
         }
         const auto params{SurfaceParams::CreateForTexture(system, config, entry)};
-        return GetSurface(gpu_addr, params, true, false).second;
+        auto pair = GetSurface(gpu_addr, params, true, false);
+        if (guard_samplers) {
+            if (sampled_textures_stack_pointer == sampled_textures_stack.size()) {
+                sampled_textures_stack.resize(sampled_textures_stack.size() * 2);
+            }
+            sampled_textures_stack[sampled_textures_stack_pointer] = pair.first;
+            sampled_textures_stack_pointer++;
+        }
+        return pair.second;
+    }
+
+    bool TextureBarrier() {
+        bool must_do = false;
+        for (u32 i = 0; i < sampled_textures_stack_pointer; i++) {
+            must_do |= sampled_textures_stack[i]->IsRenderTarget();
+            sampled_textures_stack[i] = nullptr;
+        }
+        sampled_textures_stack_pointer = 0;
+        return must_do;
     }
 
     TView GetDepthBufferSurface(bool preserve_contents) {
@@ -239,6 +261,7 @@ protected:
         make_siblings(PixelFormat::Z16, PixelFormat::R16F);
         make_siblings(PixelFormat::Z32F, PixelFormat::R32F);
         make_siblings(PixelFormat::Z32FS8, PixelFormat::RG32F);
+        sampled_textures_stack.resize(64);
     }
 
     ~TextureCache() = default;
@@ -275,7 +298,7 @@ protected:
     }
 
     void Unregister(TSurface surface) {
-        if (guard_cache && surface->IsProtected()) {
+        if (guard_render_targets && surface->IsProtected()) {
             return;
         }
         const GPUVAddr gpu_addr = surface->GetGpuAddr();
@@ -766,7 +789,8 @@ private:
     u64 ticks{};
 
     // Guards the cache for protection conflicts.
-    bool guard_cache{};
+    bool guard_render_targets{};
+    bool guard_samplers{};
 
     // The siblings table is for formats that can inter exchange with one another
     // without causing issues. This is only valid when a conflict occurs on a non
@@ -792,6 +816,9 @@ private:
         render_targets;
     FramebufferTargetInfo depth_buffer;
 
+    std::vector<TSurface> sampled_textures_stack{};
+    u32 sampled_textures_stack_pointer{};
+
     StagingCache staging_cache;
     std::recursive_mutex mutex;
 };