diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index d890076f8..9ce20f8f4 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -49,8 +49,26 @@ MICROPROFILE_DEFINE(OpenGL_Blits, "OpenGL", "Blits", MP_RGB(128, 128, 192));
 MICROPROFILE_DEFINE(OpenGL_CacheManagement, "OpenGL", "Cache Mgmt", MP_RGB(100, 255, 100));
 MICROPROFILE_DEFINE(OpenGL_PrimitiveAssembly, "OpenGL", "Prim Asmbl", MP_RGB(255, 100, 100));
 
-static std::size_t GetConstBufferSize(const Tegra::Engines::ConstBufferInfo& buffer,
-                                      const GLShader::ConstBufferEntry& entry) {
+namespace {
+
+template <typename Engine, typename Entry>
+Tegra::Texture::FullTextureInfo GetTextureInfo(const Engine& engine, const Entry& entry,
+                                               Tegra::Engines::ShaderType shader_type) {
+    if (entry.IsBindless()) {
+        const Tegra::Texture::TextureHandle tex_handle =
+            engine.AccessConstBuffer32(shader_type, entry.GetBuffer(), entry.GetOffset());
+        return engine.GetTextureInfo(tex_handle);
+    }
+    if constexpr (std::is_same_v<Engine, Tegra::Engines::Maxwell3D>) {
+        const auto stage = static_cast<Maxwell::ShaderStage>(shader_type);
+        return engine.GetStageTexture(stage, entry.GetOffset());
+    } else {
+        return engine.GetTexture(entry.GetOffset());
+    }
+}
+
+std::size_t GetConstBufferSize(const Tegra::Engines::ConstBufferInfo& buffer,
+                               const GLShader::ConstBufferEntry& entry) {
     if (!entry.IsIndirect()) {
         return entry.GetSize();
     }
@@ -64,6 +82,8 @@ static std::size_t GetConstBufferSize(const Tegra::Engines::ConstBufferInfo& buf
     return buffer.size;
 }
 
+} // Anonymous namespace
+
 RasterizerOpenGL::RasterizerOpenGL(Core::System& system, Core::Frontend::EmuWindow& emu_window,
                                    ScreenInfo& info)
     : texture_cache{system, *this, device}, shader_cache{*this, system, emu_window, device},
@@ -272,6 +292,7 @@ void RasterizerOpenGL::SetupShaders(GLenum primitive_mode) {
         SetupDrawConstBuffers(stage, shader);
         SetupDrawGlobalMemory(stage, shader);
         SetupDrawTextures(stage, shader, base_bindings);
+        SetupDrawImages(stage, shader, base_bindings);
 
         const ProgramVariant variant(base_bindings, primitive_mode);
         const auto [program_handle, next_bindings] = shader->GetHandle(variant);
@@ -921,18 +942,11 @@ void RasterizerOpenGL::SetupDrawTextures(Maxwell::ShaderStage stage, const Shade
     ASSERT_MSG(base_bindings.sampler + entries.size() <= std::size(state.textures),
                "Exceeded the number of active textures.");
 
-    for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
+    const auto num_entries = static_cast<u32>(entries.size());
+    for (u32 bindpoint = 0; bindpoint < num_entries; ++bindpoint) {
         const auto& entry = entries[bindpoint];
-        const auto texture = [&] {
-            if (!entry.IsBindless()) {
-                return maxwell3d.GetStageTexture(stage, entry.GetOffset());
-            }
-            const auto shader_type = static_cast<Tegra::Engines::ShaderType>(stage);
-            const Tegra::Texture::TextureHandle tex_handle =
-                maxwell3d.AccessConstBuffer32(shader_type, entry.GetBuffer(), entry.GetOffset());
-            return maxwell3d.GetTextureInfo(tex_handle);
-        }();
-
+        const auto shader_type = static_cast<Tegra::Engines::ShaderType>(stage);
+        const auto texture = GetTextureInfo(maxwell3d, entry, shader_type);
         SetupTexture(base_bindings.sampler + bindpoint, texture, entry);
     }
 }
@@ -945,17 +959,10 @@ void RasterizerOpenGL::SetupComputeTextures(const Shader& kernel) {
     ASSERT_MSG(entries.size() <= std::size(state.textures),
                "Exceeded the number of active textures.");
 
-    for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
+    const auto num_entries = static_cast<u32>(entries.size());
+    for (u32 bindpoint = 0; bindpoint < num_entries; ++bindpoint) {
         const auto& entry = entries[bindpoint];
-        const auto texture = [&] {
-            if (!entry.IsBindless()) {
-                return compute.GetTexture(entry.GetOffset());
-            }
-            const Tegra::Texture::TextureHandle tex_handle = compute.AccessConstBuffer32(
-                Tegra::Engines::ShaderType::Compute, entry.GetBuffer(), entry.GetOffset());
-            return compute.GetTextureInfo(tex_handle);
-        }();
-
+        const auto texture = GetTextureInfo(compute, entry, Tegra::Engines::ShaderType::Compute);
         SetupTexture(bindpoint, texture, entry);
     }
 }
@@ -981,19 +988,28 @@ void RasterizerOpenGL::SetupTexture(u32 binding, const Tegra::Texture::FullTextu
                        texture.tic.w_source);
 }
 
+void RasterizerOpenGL::SetupDrawImages(Maxwell::ShaderStage stage, const Shader& shader,
+                                       BaseBindings base_bindings) {
+    const auto& maxwell3d = system.GPU().Maxwell3D();
+    const auto& entries = shader->GetShaderEntries().images;
+
+    const auto num_entries = static_cast<u32>(entries.size());
+    for (u32 bindpoint = 0; bindpoint < num_entries; ++bindpoint) {
+        const auto& entry = entries[bindpoint];
+        const auto shader_type = static_cast<Tegra::Engines::ShaderType>(stage);
+        const auto tic = GetTextureInfo(maxwell3d, entry, shader_type).tic;
+        SetupImage(base_bindings.image + bindpoint, tic, entry);
+    }
+}
+
 void RasterizerOpenGL::SetupComputeImages(const Shader& shader) {
     const auto& compute = system.GPU().KeplerCompute();
     const auto& entries = shader->GetShaderEntries().images;
-    for (u32 bindpoint = 0; bindpoint < entries.size(); ++bindpoint) {
+
+    const auto num_entries = static_cast<u32>(entries.size());
+    for (u32 bindpoint = 0; bindpoint < num_entries; ++bindpoint) {
         const auto& entry = entries[bindpoint];
-        const auto tic = [&] {
-            if (!entry.IsBindless()) {
-                return compute.GetTexture(entry.GetOffset()).tic;
-            }
-            const Tegra::Texture::TextureHandle tex_handle = compute.AccessConstBuffer32(
-                Tegra::Engines::ShaderType::Compute, entry.GetBuffer(), entry.GetOffset());
-            return compute.GetTextureInfo(tex_handle).tic;
-        }();
+        const auto tic = GetTextureInfo(compute, entry, Tegra::Engines::ShaderType::Compute).tic;
         SetupImage(bindpoint, tic, entry);
     }
 }
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index 0e0819d59..267ed7803 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -118,6 +118,10 @@ private:
     void SetupTexture(u32 binding, const Tegra::Texture::FullTextureInfo& texture,
                       const GLShader::SamplerEntry& entry);
 
+    /// Configures images in a graphics shader.
+    void SetupDrawImages(Tegra::Engines::Maxwell3D::Regs::ShaderStage stage, const Shader& shader,
+                         BaseBindings base_bindings);
+
     /// Configures images in a compute shader.
     void SetupComputeImages(const Shader& shader);
 
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp
index b23a982d7..e7c92e45d 100644
--- a/src/video_core/renderer_opengl/gl_shader_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp
@@ -449,6 +449,7 @@ std::tuple<GLuint, BaseBindings> CachedShader::GetHandle(const ProgramVariant& v
     base_bindings.cbuf += STAGE_RESERVED_UBOS;
     base_bindings.gmem += static_cast<u32>(entries.global_memory_entries.size());
     base_bindings.sampler += static_cast<u32>(entries.samplers.size());
+    base_bindings.image += static_cast<u32>(entries.images.size());
 
     return {program->handle, base_bindings};
 }
diff --git a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
index 5ebcbbbba..ccf530367 100644
--- a/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_disk_cache.cpp
@@ -52,7 +52,7 @@ struct BindlessSamplerKey {
     Tegra::Engines::SamplerDescriptor sampler{};
 };
 
-constexpr u32 NativeVersion = 9;
+constexpr u32 NativeVersion = 10;
 
 // Making sure sizes doesn't change by accident
 static_assert(sizeof(BaseBindings) == 16);