diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index 0184342a07..3b3c82f411 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -62,6 +62,7 @@ public:
         static constexpr std::size_t NumVertexAttributes = 32;
         static constexpr std::size_t NumVaryings = 31;
         static constexpr std::size_t NumTextureSamplers = 32;
+        static constexpr std::size_t NumImages = 8; // TODO(Rodrigo): Investigate this number
         static constexpr std::size_t NumClipDistances = 8;
         static constexpr std::size_t MaxShaderProgram = 6;
         static constexpr std::size_t MaxShaderStage = 5;
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 8a59b86e38..6636b3c74e 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -1022,7 +1022,7 @@ bool RasterizerOpenGL::SetupTexture(const Shader& shader, u32 binding,
     auto& unit{state.texture_units[binding]};
     unit.sampler = sampler_cache.GetSampler(texture.tsc);
 
-    const auto view = texture_cache.GetImageSurface(texture.tic, entry);
+    const auto view = texture_cache.GetTextureSurface(texture.tic, entry);
     if (!view) {
         // Can occur when texture addr is null or its memory is unmapped/invalid
         unit.texture = 0;
@@ -1054,7 +1054,12 @@ void RasterizerOpenGL::SetupComputeImages(const Shader& shader) {
             tex_handle.raw = compute.AccessConstBuffer32(cbuf.first, cbuf.second);
             return compute.GetTextureInfo(tex_handle, entry.GetOffset());
         }();
-        UNIMPLEMENTED();
+        const auto view = texture_cache.GetImageSurface(texture.tic, entry);
+        if (!view) {
+            state.images[bindpoint] = 0;
+            continue;
+        }
+        state.images[bindpoint] = view->GetTexture();
     }
 }
 
diff --git a/src/video_core/texture_cache/surface_params.cpp b/src/video_core/texture_cache/surface_params.cpp
index 2f8bd399cf..1e4d3fb795 100644
--- a/src/video_core/texture_cache/surface_params.cpp
+++ b/src/video_core/texture_cache/surface_params.cpp
@@ -24,45 +24,53 @@ using VideoCore::Surface::SurfaceTarget;
 using VideoCore::Surface::SurfaceTargetFromTextureType;
 using VideoCore::Surface::SurfaceType;
 
-SurfaceTarget TextureType2SurfaceTarget(Tegra::Shader::TextureType type, bool is_array) {
+namespace {
+
+SurfaceTarget TextureTypeToSurfaceTarget(Tegra::Shader::TextureType type, bool is_array) {
     switch (type) {
-    case Tegra::Shader::TextureType::Texture1D: {
-        if (is_array)
-            return SurfaceTarget::Texture1DArray;
-        else
-            return SurfaceTarget::Texture1D;
-    }
-    case Tegra::Shader::TextureType::Texture2D: {
-        if (is_array)
-            return SurfaceTarget::Texture2DArray;
-        else
-            return SurfaceTarget::Texture2D;
-    }
-    case Tegra::Shader::TextureType::Texture3D: {
+    case Tegra::Shader::TextureType::Texture1D:
+        return is_array ? SurfaceTarget::Texture1DArray : SurfaceTarget::Texture1D;
+    case Tegra::Shader::TextureType::Texture2D:
+        return is_array ? SurfaceTarget::Texture2DArray : SurfaceTarget::Texture2D;
+    case Tegra::Shader::TextureType::Texture3D:
         ASSERT(!is_array);
         return SurfaceTarget::Texture3D;
-    }
-    case Tegra::Shader::TextureType::TextureCube: {
-        if (is_array)
-            return SurfaceTarget::TextureCubeArray;
-        else
-            return SurfaceTarget::TextureCubemap;
-    }
-    default: {
+    case Tegra::Shader::TextureType::TextureCube:
+        return is_array ? SurfaceTarget::TextureCubeArray : SurfaceTarget::TextureCubemap;
+    default:
         UNREACHABLE();
         return SurfaceTarget::Texture2D;
     }
+}
+
+SurfaceTarget ImageTypeToSurfaceTarget(Tegra::Shader::ImageType type) {
+    switch (type) {
+    case Tegra::Shader::ImageType::Texture1D:
+        return SurfaceTarget::Texture1D;
+    case Tegra::Shader::ImageType::TextureBuffer:
+        return SurfaceTarget::TextureBuffer;
+    case Tegra::Shader::ImageType::Texture1DArray:
+        return SurfaceTarget::Texture1DArray;
+    case Tegra::Shader::ImageType::Texture2D:
+        return SurfaceTarget::Texture2D;
+    case Tegra::Shader::ImageType::Texture2DArray:
+        return SurfaceTarget::Texture2DArray;
+    case Tegra::Shader::ImageType::Texture3D:
+        return SurfaceTarget::Texture3D;
+    default:
+        UNREACHABLE();
+        return SurfaceTarget::Texture2D;
     }
 }
 
-namespace {
 constexpr u32 GetMipmapSize(bool uncompressed, u32 mip_size, u32 tile) {
     return uncompressed ? mip_size : std::max(1U, (mip_size + tile - 1) / tile);
 }
+
 } // Anonymous namespace
 
-SurfaceParams SurfaceParams::CreateForImage(const Tegra::Texture::TICEntry& tic,
-                                            const VideoCommon::Shader::Sampler& entry) {
+SurfaceParams SurfaceParams::CreateForTexture(const Tegra::Texture::TICEntry& tic,
+                                              const VideoCommon::Shader::Sampler& entry) {
     SurfaceParams params;
     params.is_tiled = tic.IsTiled();
     params.srgb_conversion = tic.IsSrgbConversionEnabled();
@@ -94,8 +102,17 @@ SurfaceParams SurfaceParams::CreateForImage(const Tegra::Texture::TICEntry& tic,
     params.component_type = ComponentTypeFromTexture(tic.r_type.Value());
     params.type = GetFormatType(params.pixel_format);
     // TODO: on 1DBuffer we should use the tic info.
-    if (!tic.IsBuffer()) {
-        params.target = TextureType2SurfaceTarget(entry.GetType(), entry.IsArray());
+    if (tic.IsBuffer()) {
+        params.target = SurfaceTarget::TextureBuffer;
+        params.width = tic.Width();
+        params.pitch = params.width * params.GetBytesPerPixel();
+        params.height = 1;
+        params.depth = 1;
+        params.num_levels = 1;
+        params.emulated_levels = 1;
+        params.is_layered = false;
+    } else {
+        params.target = TextureTypeToSurfaceTarget(entry.GetType(), entry.IsArray());
         params.width = tic.Width();
         params.height = tic.Height();
         params.depth = tic.Depth();
@@ -107,7 +124,27 @@ SurfaceParams SurfaceParams::CreateForImage(const Tegra::Texture::TICEntry& tic,
         params.num_levels = tic.max_mip_level + 1;
         params.emulated_levels = std::min(params.num_levels, params.MaxPossibleMipmap());
         params.is_layered = params.IsLayered();
-    } else {
+    }
+    return params;
+}
+
+SurfaceParams SurfaceParams::CreateForImage(const Tegra::Texture::TICEntry& tic,
+                                            const VideoCommon::Shader::Image& entry) {
+    SurfaceParams params;
+    params.is_tiled = tic.IsTiled();
+    params.srgb_conversion = tic.IsSrgbConversionEnabled();
+    params.block_width = params.is_tiled ? tic.BlockWidth() : 0,
+    params.block_height = params.is_tiled ? tic.BlockHeight() : 0,
+    params.block_depth = params.is_tiled ? tic.BlockDepth() : 0,
+    params.tile_width_spacing = params.is_tiled ? (1 << tic.tile_width_spacing.Value()) : 1;
+    params.pixel_format =
+        PixelFormatFromTextureFormat(tic.format, tic.r_type.Value(), params.srgb_conversion);
+    params.type = GetFormatType(params.pixel_format);
+    params.component_type = ComponentTypeFromTexture(tic.r_type.Value());
+    params.type = GetFormatType(params.pixel_format);
+    params.target = ImageTypeToSurfaceTarget(entry.GetType());
+    // TODO: on 1DBuffer we should use the tic info.
+    if (tic.IsBuffer()) {
         params.target = SurfaceTarget::TextureBuffer;
         params.width = tic.Width();
         params.pitch = params.width * params.GetBytesPerPixel();
@@ -116,6 +153,18 @@ SurfaceParams SurfaceParams::CreateForImage(const Tegra::Texture::TICEntry& tic,
         params.num_levels = 1;
         params.emulated_levels = 1;
         params.is_layered = false;
+    } else {
+        params.width = tic.Width();
+        params.height = tic.Height();
+        params.depth = tic.Depth();
+        params.pitch = params.is_tiled ? 0 : tic.Pitch();
+        if (params.target == SurfaceTarget::TextureCubemap ||
+            params.target == SurfaceTarget::TextureCubeArray) {
+            params.depth *= 6;
+        }
+        params.num_levels = tic.max_mip_level + 1;
+        params.emulated_levels = std::min(params.num_levels, params.MaxPossibleMipmap());
+        params.is_layered = params.IsLayered();
     }
     return params;
 }
diff --git a/src/video_core/texture_cache/surface_params.h b/src/video_core/texture_cache/surface_params.h
index ee2efa5941..1011a4d8e7 100644
--- a/src/video_core/texture_cache/surface_params.h
+++ b/src/video_core/texture_cache/surface_params.h
@@ -23,8 +23,12 @@ using VideoCore::Surface::SurfaceCompression;
 class SurfaceParams {
 public:
     /// Creates SurfaceCachedParams from a texture configuration.
+    static SurfaceParams CreateForTexture(const Tegra::Texture::TICEntry& tic,
+                                          const VideoCommon::Shader::Sampler& entry);
+
+    /// Creates SurfaceCachedParams from an image configuration.
     static SurfaceParams CreateForImage(const Tegra::Texture::TICEntry& tic,
-                                        const VideoCommon::Shader::Sampler& entry);
+                                        const VideoCommon::Shader::Image& entry);
 
     /// Creates SurfaceCachedParams for a depth buffer configuration.
     static SurfaceParams CreateForDepthBuffer(
diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h
index 623cce0685..877c6635d6 100644
--- a/src/video_core/texture_cache/texture_cache.h
+++ b/src/video_core/texture_cache/texture_cache.h
@@ -89,8 +89,23 @@ public:
         }
     }
 
+    TView GetTextureSurface(const Tegra::Texture::TICEntry& tic,
+                            const VideoCommon::Shader::Sampler& entry) {
+        std::lock_guard lock{mutex};
+        const auto gpu_addr{tic.Address()};
+        if (!gpu_addr) {
+            return {};
+        }
+        const auto params{SurfaceParams::CreateForTexture(tic, entry)};
+        const auto [surface, view] = GetSurface(gpu_addr, params, true, false);
+        if (guard_samplers) {
+            sampled_textures.push_back(surface);
+        }
+        return view;
+    }
+
     TView GetImageSurface(const Tegra::Texture::TICEntry& tic,
-                          const VideoCommon::Shader::Sampler& entry) {
+                          const VideoCommon::Shader::Image& entry) {
         std::lock_guard lock{mutex};
         const auto gpu_addr{tic.Address()};
         if (!gpu_addr) {