diff --git a/Ryujinx.Graphics.GAL/IPipeline.cs b/Ryujinx.Graphics.GAL/IPipeline.cs
index aec096e72e..83afcaa3a8 100644
--- a/Ryujinx.Graphics.GAL/IPipeline.cs
+++ b/Ryujinx.Graphics.GAL/IPipeline.cs
@@ -10,9 +10,10 @@ namespace Ryujinx.Graphics.GAL
 
         void ClearBuffer(BufferHandle destination, int offset, int size, uint value);
 
-        void ClearRenderTargetColor(int index, uint componentMask, ColorF color);
+        void ClearRenderTargetColor(int index, int layer, uint componentMask, ColorF color);
 
         void ClearRenderTargetDepthStencil(
+            int layer,
             float depthValue,
             bool depthMask,
             int stencilValue,
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetColorCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetColorCommand.cs
index 57509f1c0f..cde69e7bb6 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetColorCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetColorCommand.cs
@@ -4,19 +4,21 @@
     {
         public CommandType CommandType => CommandType.ClearRenderTargetColor;
         private int _index;
+        private int _layer;
         private uint _componentMask;
         private ColorF _color;
 
-        public void Set(int index, uint componentMask, ColorF color)
+        public void Set(int index, int layer, uint componentMask, ColorF color)
         {
             _index = index;
+            _layer = layer;
             _componentMask = componentMask;
             _color = color;
         }
 
         public static void Run(ref ClearRenderTargetColorCommand command, ThreadedRenderer threaded, IRenderer renderer)
         {
-            renderer.Pipeline.ClearRenderTargetColor(command._index, command._componentMask, command._color);
+            renderer.Pipeline.ClearRenderTargetColor(command._index, command._layer, command._componentMask, command._color);
         }
     }
 }
diff --git a/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetDepthStencilCommand.cs b/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetDepthStencilCommand.cs
index 3692cd37b3..c5c76539e3 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetDepthStencilCommand.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/Commands/ClearRenderTargetDepthStencilCommand.cs
@@ -3,13 +3,15 @@
     struct ClearRenderTargetDepthStencilCommand : IGALCommand
     {
         public CommandType CommandType => CommandType.ClearRenderTargetDepthStencil;
+        private int _layer;
         private float _depthValue;
         private bool _depthMask;
         private int _stencilValue;
         private int _stencilMask;
 
-        public void Set(float depthValue, bool depthMask, int stencilValue, int stencilMask)
+        public void Set(int layer, float depthValue, bool depthMask, int stencilValue, int stencilMask)
         {
+            _layer = layer;
             _depthValue = depthValue;
             _depthMask = depthMask;
             _stencilValue = stencilValue;
@@ -18,7 +20,7 @@
 
         public static void Run(ref ClearRenderTargetDepthStencilCommand command, ThreadedRenderer threaded, IRenderer renderer)
         {
-            renderer.Pipeline.ClearRenderTargetDepthStencil(command._depthValue, command._depthMask, command._stencilValue, command._stencilMask);
+            renderer.Pipeline.ClearRenderTargetDepthStencil(command._layer, command._depthValue, command._depthMask, command._stencilValue, command._stencilMask);
         }
     }
 }
diff --git a/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs b/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs
index 010ee7e650..2a1f474a9e 100644
--- a/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs
+++ b/Ryujinx.Graphics.GAL/Multithreading/ThreadedPipeline.cs
@@ -40,15 +40,15 @@ namespace Ryujinx.Graphics.GAL.Multithreading
             _renderer.QueueCommand();
         }
 
-        public void ClearRenderTargetColor(int index, uint componentMask, ColorF color)
+        public void ClearRenderTargetColor(int index, int layer, uint componentMask, ColorF color)
         {
-            _renderer.New<ClearRenderTargetColorCommand>().Set(index, componentMask, color);
+            _renderer.New<ClearRenderTargetColorCommand>().Set(index, layer, componentMask, color);
             _renderer.QueueCommand();
         }
 
-        public void ClearRenderTargetDepthStencil(float depthValue, bool depthMask, int stencilValue, int stencilMask)
+        public void ClearRenderTargetDepthStencil(int layer, float depthValue, bool depthMask, int stencilValue, int stencilMask)
         {
-            _renderer.New<ClearRenderTargetDepthStencilCommand>().Set(depthValue, depthMask, stencilValue, stencilMask);
+            _renderer.New<ClearRenderTargetDepthStencilCommand>().Set(layer, depthValue, depthMask, stencilValue, stencilMask);
             _renderer.QueueCommand();
         }
 
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
index ab37131412..f90baf99e2 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
@@ -505,8 +505,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
             }
 
             int index = (argument >> 6) & 0xf;
+            int layer = (argument >> 10) & 0x3ff;
 
-            engine.UpdateRenderTargetState(useControl: false, singleUse: index);
+            engine.UpdateRenderTargetState(useControl: false, layered: layer != 0, singleUse: index);
 
             // If there is a mismatch on the host clip region and the one explicitly defined by the guest
             // on the screen scissor state, then we need to force only one texture to be bound to avoid
@@ -581,7 +582,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
 
                 ColorF color = new ColorF(clearColor.Red, clearColor.Green, clearColor.Blue, clearColor.Alpha);
 
-                _context.Renderer.Pipeline.ClearRenderTargetColor(index, componentMask, color);
+                _context.Renderer.Pipeline.ClearRenderTargetColor(index, layer, componentMask, color);
             }
 
             if (clearDepth || clearStencil)
@@ -602,6 +603,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
                 }
 
                 _context.Renderer.Pipeline.ClearRenderTargetDepthStencil(
+                    layer,
                     depthValue,
                     clearDepth,
                     stencilValue,
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
index d0c3bc5ae9..f648479b66 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
@@ -362,8 +362,9 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
         /// Updates render targets (color and depth-stencil buffers) based on current render target state.
         /// </summary>
         /// <param name="useControl">Use draw buffers information from render target control register</param>
+        /// <param name="layered">Indicates if the texture is layered</param>
         /// <param name="singleUse">If this is not -1, it indicates that only the given indexed target will be used.</param>
-        public void UpdateRenderTargetState(bool useControl, int singleUse = -1)
+        public void UpdateRenderTargetState(bool useControl, bool layered = false, int singleUse = -1)
         {
             var memoryManager = _channel.MemoryManager;
             var rtControl = _state.State.RtControl;
@@ -399,7 +400,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
                 Image.Texture color = memoryManager.Physical.TextureCache.FindOrCreateTexture(
                     memoryManager,
                     colorState,
-                    _vtgWritesRtLayer,
+                    _vtgWritesRtLayer || layered,
                     samplesInX,
                     samplesInY,
                     sizeHint);
@@ -433,6 +434,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
                     memoryManager,
                     dsState,
                     dsSize,
+                    _vtgWritesRtLayer || layered,
                     samplesInX,
                     samplesInY,
                     sizeHint);
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs
index a2e8c64c15..764ba23945 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs
@@ -131,10 +131,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
         /// Updates render targets (color and depth-stencil buffers) based on current render target state.
         /// </summary>
         /// <param name="useControl">Use draw buffers information from render target control register</param>
+        /// <param name="layered">Indicates if the texture is layered</param>
         /// <param name="singleUse">If this is not -1, it indicates that only the given indexed target will be used.</param>
-        public void UpdateRenderTargetState(bool useControl, int singleUse = -1)
+        public void UpdateRenderTargetState(bool useControl, bool layered = false, int singleUse = -1)
         {
-            _stateUpdater.UpdateRenderTargetState(useControl, singleUse);
+            _stateUpdater.UpdateRenderTargetState(useControl, layered, singleUse);
         }
 
         /// <summary>
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
index 0454105717..ba863a1e1f 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
@@ -349,6 +349,7 @@ namespace Ryujinx.Graphics.Gpu.Image
         /// <param name="memoryManager">GPU memory manager where the texture is mapped</param>
         /// <param name="dsState">Depth-stencil buffer texture to find or create</param>
         /// <param name="size">Size of the depth-stencil texture</param>
+        /// <param name="layered">Indicates if the texture might be accessed with a non-zero layer index</param>
         /// <param name="samplesInX">Number of samples in the X direction, for MSAA</param>
         /// <param name="samplesInY">Number of samples in the Y direction, for MSAA</param>
         /// <param name="sizeHint">A hint indicating the minimum used size for the texture</param>
@@ -357,6 +358,7 @@ namespace Ryujinx.Graphics.Gpu.Image
             MemoryManager memoryManager,
             RtDepthStencilState dsState,
             Size3D size,
+            bool layered,
             int samplesInX,
             int samplesInY,
             Size sizeHint)
@@ -364,9 +366,24 @@ namespace Ryujinx.Graphics.Gpu.Image
             int gobBlocksInY = dsState.MemoryLayout.UnpackGobBlocksInY();
             int gobBlocksInZ = dsState.MemoryLayout.UnpackGobBlocksInZ();
 
-            Target target = (samplesInX | samplesInY) != 1
-                ? Target.Texture2DMultisample
-                : Target.Texture2D;
+            Target target;
+
+            if (dsState.MemoryLayout.UnpackIsTarget3D())
+            {
+                target = Target.Texture3D;
+            }
+            else if ((samplesInX | samplesInY) != 1)
+            {
+                target = size.Depth > 1 && layered
+                    ? Target.Texture2DMultisampleArray
+                    : Target.Texture2DMultisample;
+            }
+            else
+            {
+                target = size.Depth > 1 && layered
+                    ? Target.Texture2DArray
+                    : Target.Texture2D;
+            }
 
             FormatInfo formatInfo = dsState.Format.Convert();
 
diff --git a/Ryujinx.Graphics.OpenGL/Framebuffer.cs b/Ryujinx.Graphics.OpenGL/Framebuffer.cs
index da928b4c87..dafa767238 100644
--- a/Ryujinx.Graphics.OpenGL/Framebuffer.cs
+++ b/Ryujinx.Graphics.OpenGL/Framebuffer.cs
@@ -9,10 +9,13 @@ namespace Ryujinx.Graphics.OpenGL
     class Framebuffer : IDisposable
     {
         public int Handle { get; private set; }
+        private int _clearFbHandle;
+        private bool _clearFbInitialized;
 
         private FramebufferAttachment _lastDsAttachment;
 
         private readonly TextureView[] _colors;
+        private TextureView _depthStencil;
 
         private int _colorsCount;
         private bool _dualSourceBlend;
@@ -20,6 +23,7 @@ namespace Ryujinx.Graphics.OpenGL
         public Framebuffer()
         {
             Handle = GL.GenFramebuffer();
+            _clearFbHandle = GL.GenFramebuffer();
 
             _colors = new TextureView[8];
         }
@@ -55,20 +59,7 @@ namespace Ryujinx.Graphics.OpenGL
 
             if (depthStencil != null)
             {
-                FramebufferAttachment attachment;
-
-                if (IsPackedDepthStencilFormat(depthStencil.Format))
-                {
-                    attachment = FramebufferAttachment.DepthStencilAttachment;
-                }
-                else if (IsDepthOnlyFormat(depthStencil.Format))
-                {
-                    attachment = FramebufferAttachment.DepthAttachment;
-                }
-                else
-                {
-                    attachment = FramebufferAttachment.StencilAttachment;
-                }
+                FramebufferAttachment attachment = GetAttachment(depthStencil.Format);
 
                 GL.FramebufferTexture(
                     FramebufferTarget.Framebuffer,
@@ -82,6 +73,8 @@ namespace Ryujinx.Graphics.OpenGL
             {
                 _lastDsAttachment = 0;
             }
+
+            _depthStencil = depthStencil;
         }
 
         public void SetDualSourceBlend(bool enable)
@@ -124,6 +117,22 @@ namespace Ryujinx.Graphics.OpenGL
             GL.DrawBuffers(colorsCount, drawBuffers);
         }
 
+        private static FramebufferAttachment GetAttachment(Format format)
+        {
+            if (IsPackedDepthStencilFormat(format))
+            {
+                return FramebufferAttachment.DepthStencilAttachment;
+            }
+            else if (IsDepthOnlyFormat(format))
+            {
+                return FramebufferAttachment.DepthAttachment;
+            }
+            else
+            {
+                return FramebufferAttachment.StencilAttachment;
+            }
+        }
+
         private static bool IsPackedDepthStencilFormat(Format format)
         {
             return format == Format.D24UnormS8Uint ||
@@ -136,6 +145,78 @@ namespace Ryujinx.Graphics.OpenGL
             return format == Format.D16Unorm || format == Format.D32Float;
         }
 
+        public void AttachColorLayerForClear(int index, int layer)
+        {
+            TextureView color = _colors[index];
+
+            if (!IsLayered(color))
+            {
+                return;
+            }
+
+            BindClearFb();
+            GL.FramebufferTextureLayer(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0 + index, color.Handle, 0, layer);
+        }
+
+        public void DetachColorLayerForClear(int index)
+        {
+            TextureView color = _colors[index];
+
+            if (!IsLayered(color))
+            {
+                return;
+            }
+
+            GL.FramebufferTexture(FramebufferTarget.Framebuffer, FramebufferAttachment.ColorAttachment0 + index, 0, 0);
+            Bind();
+        }
+
+        public void AttachDepthStencilLayerForClear(int layer)
+        {
+            TextureView depthStencil = _depthStencil;
+
+            if (!IsLayered(depthStencil))
+            {
+                return;
+            }
+
+            BindClearFb();
+            GL.FramebufferTextureLayer(FramebufferTarget.Framebuffer, GetAttachment(depthStencil.Format), depthStencil.Handle, 0, layer);
+        }
+
+        public void DetachDepthStencilLayerForClear()
+        {
+            TextureView depthStencil = _depthStencil;
+
+            if (!IsLayered(depthStencil))
+            {
+                return;
+            }
+
+            GL.FramebufferTexture(FramebufferTarget.Framebuffer, GetAttachment(depthStencil.Format), 0, 0);
+            Bind();
+        }
+
+        private void BindClearFb()
+        {
+            GL.BindFramebuffer(FramebufferTarget.Framebuffer, _clearFbHandle);
+
+            if (!_clearFbInitialized)
+            {
+                SetDrawBuffersImpl(Constants.MaxRenderTargets);
+                _clearFbInitialized = true;
+            }
+        }
+
+        private static bool IsLayered(TextureView view)
+        {
+            return view != null &&
+                   view.Target != Target.Texture1D &&
+                   view.Target != Target.Texture2D &&
+                   view.Target != Target.Texture2DMultisample &&
+                   view.Target != Target.TextureBuffer;
+        }
+
         public void Dispose()
         {
             if (Handle != 0)
@@ -144,6 +225,13 @@ namespace Ryujinx.Graphics.OpenGL
 
                 Handle = 0;
             }
+
+            if (_clearFbHandle != 0)
+            {
+                GL.DeleteFramebuffer(_clearFbHandle);
+
+                _clearFbHandle = 0;
+            }
         }
     }
 }
diff --git a/Ryujinx.Graphics.OpenGL/Pipeline.cs b/Ryujinx.Graphics.OpenGL/Pipeline.cs
index 637e4606e9..62d4dee900 100644
--- a/Ryujinx.Graphics.OpenGL/Pipeline.cs
+++ b/Ryujinx.Graphics.OpenGL/Pipeline.cs
@@ -110,7 +110,7 @@ namespace Ryujinx.Graphics.OpenGL
             Buffer.Clear(destination, offset, size, value);
         }
 
-        public void ClearRenderTargetColor(int index, uint componentMask, ColorF color)
+        public void ClearRenderTargetColor(int index, int layer, uint componentMask, ColorF color)
         {
             GL.ColorMask(
                 index,
@@ -119,14 +119,18 @@ namespace Ryujinx.Graphics.OpenGL
                 (componentMask & 4) != 0,
                 (componentMask & 8) != 0);
 
+            _framebuffer.AttachColorLayerForClear(index, layer);
+
             float[] colors = new float[] { color.Red, color.Green, color.Blue, color.Alpha };
 
             GL.ClearBuffer(OpenTK.Graphics.OpenGL.ClearBuffer.Color, index, colors);
 
+            _framebuffer.DetachColorLayerForClear(index);
+
             RestoreComponentMask(index);
         }
 
-        public void ClearRenderTargetDepthStencil(float depthValue, bool depthMask, int stencilValue, int stencilMask)
+        public void ClearRenderTargetDepthStencil(int layer, float depthValue, bool depthMask, int stencilValue, int stencilMask)
         {
             bool stencilMaskChanged =
                 stencilMask != 0 &&
@@ -144,6 +148,8 @@ namespace Ryujinx.Graphics.OpenGL
                 GL.DepthMask(depthMask);
             }
 
+            _framebuffer.AttachDepthStencilLayerForClear(layer);
+
             if (depthMask && stencilMask != 0)
             {
                 GL.ClearBuffer(ClearBufferCombined.DepthStencil, 0, depthValue, stencilValue);
@@ -157,6 +163,8 @@ namespace Ryujinx.Graphics.OpenGL
                 GL.ClearBuffer(OpenTK.Graphics.OpenGL.ClearBuffer.Stencil, 0, ref stencilValue);
             }
 
+            _framebuffer.DetachDepthStencilLayerForClear();
+
             if (stencilMaskChanged)
             {
                 GL.StencilMaskSeparate(StencilFace.Front, _stencilFrontMask);