diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
index 0f249512b0..61f227d936 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/DrawManager.cs
@@ -725,10 +725,25 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
                 return;
             }
 
+            bool clearDepth = (argument & 1) != 0;
+            bool clearStencil = (argument & 2) != 0;
+            uint componentMask = (uint)((argument >> 2) & 0xf);
             int index = (argument >> 6) & 0xf;
             int layer = (argument >> 10) & 0x3ff;
 
-            engine.UpdateRenderTargetState(useControl: false, layered: layer != 0 || layerCount > 1, singleUse: index);
+            RenderTargetUpdateFlags updateFlags = RenderTargetUpdateFlags.SingleColor;
+
+            if (layer != 0 || layerCount > 1)
+            {
+                updateFlags |= RenderTargetUpdateFlags.Layered;
+            }
+
+            if (clearDepth || clearStencil)
+            {
+                updateFlags |= RenderTargetUpdateFlags.UpdateDepthStencil;
+            }
+
+            engine.UpdateRenderTargetState(updateFlags, singleUse: componentMask != 0 ? index : -1);
 
             // 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
@@ -788,18 +803,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
                 _context.Renderer.Pipeline.SetScissors(scissors);
             }
 
-            if (clipMismatch)
-            {
-                _channel.TextureManager.UpdateRenderTarget(index);
-            }
-            else
-            {
-                _channel.TextureManager.UpdateRenderTargets();
-            }
-
-            bool clearDepth = (argument & 1) != 0;
-            bool clearStencil = (argument & 2) != 0;
-            uint componentMask = (uint)((argument >> 2) & 0xf);
+            _channel.TextureManager.UpdateRenderTargets();
 
             if (componentMask != 0)
             {
@@ -841,7 +845,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
                 engine.UpdateScissorState();
             }
 
-            engine.UpdateRenderTargetState(useControl: true);
+            engine.UpdateRenderTargetState(RenderTargetUpdateFlags.UpdateAll);
 
             if (renderEnable == ConditionalRenderEnabled.Host)
             {
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/RenderTargetUpdateFlags.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/RenderTargetUpdateFlags.cs
new file mode 100644
index 0000000000..cf2e818ceb
--- /dev/null
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/RenderTargetUpdateFlags.cs
@@ -0,0 +1,41 @@
+using System;
+
+namespace Ryujinx.Graphics.Gpu.Engine.Threed
+{
+    /// <summary>
+    /// Flags indicating how the render targets should be updated.
+    /// </summary>
+    [Flags]
+    enum RenderTargetUpdateFlags
+    {
+        /// <summary>
+        /// No flags.
+        /// </summary>
+        None = 0,
+
+        /// <summary>
+        /// Get render target index from the control register.
+        /// </summary>
+        UseControl = 1 << 0,
+
+        /// <summary>
+        /// Indicates that all render targets are 2D array textures.
+        /// </summary>
+        Layered = 1 << 1,
+
+        /// <summary>
+        /// Indicates that only a single color target will be used.
+        /// </summary>
+        SingleColor = 1 << 2,
+
+        /// <summary>
+        /// Indicates that the depth-stencil target will be used.
+        /// </summary>
+        UpdateDepthStencil = 1 << 3,
+
+        /// <summary>
+        /// Default update flags for draw.
+        /// </summary>
+        UpdateAll = UseControl | UpdateDepthStencil
+    }
+}
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
index 9b59009cfb..9b58e0148a 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/StateUpdater.cs
@@ -402,20 +402,23 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
         /// </summary>
         private void UpdateRenderTargetState()
         {
-            UpdateRenderTargetState(true);
+            UpdateRenderTargetState(RenderTargetUpdateFlags.UpdateAll);
         }
 
         /// <summary>
         /// 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="updateFlags">Flags indicating which render targets should be updated and how</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, bool layered = false, int singleUse = -1)
+        public void UpdateRenderTargetState(RenderTargetUpdateFlags updateFlags, int singleUse = -1)
         {
             var memoryManager = _channel.MemoryManager;
             var rtControl = _state.State.RtControl;
 
+            bool useControl = updateFlags.HasFlag(RenderTargetUpdateFlags.UseControl);
+            bool layered = updateFlags.HasFlag(RenderTargetUpdateFlags.Layered);
+            bool singleColor = updateFlags.HasFlag(RenderTargetUpdateFlags.SingleColor);
+
             int count = useControl ? rtControl.UnpackCount() : Constants.TotalRenderTargets;
 
             var msaaMode = _state.State.RtMsaaMode;
@@ -438,7 +441,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
 
                 var colorState = _state.State.RtColorState[rtIndex];
 
-                if (index >= count || !IsRtEnabled(colorState))
+                if (index >= count || !IsRtEnabled(colorState) || (singleColor && index != singleUse))
                 {
                     changedScale |= _channel.TextureManager.SetRenderTargetColor(index, null);
 
@@ -478,7 +481,7 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
 
             Image.Texture depthStencil = null;
 
-            if (dsEnable)
+            if (dsEnable && updateFlags.HasFlag(RenderTargetUpdateFlags.UpdateDepthStencil))
             {
                 var dsState = _state.State.RtDepthStencilState;
                 var dsSize = _state.State.RtDepthStencilSize;
diff --git a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs
index 19eb8b46ee..9a447a0bd9 100644
--- a/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs
+++ b/Ryujinx.Graphics.Gpu/Engine/Threed/ThreedClass.cs
@@ -139,12 +139,11 @@ namespace Ryujinx.Graphics.Gpu.Engine.Threed
         /// <summary>
         /// 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="updateFlags">Flags indicating which render targets should be updated and how</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, bool layered = false, int singleUse = -1)
+        public void UpdateRenderTargetState(RenderTargetUpdateFlags updateFlags, int singleUse = -1)
         {
-            _stateUpdater.UpdateRenderTargetState(useControl, layered, singleUse);
+            _stateUpdater.UpdateRenderTargetState(updateFlags, singleUse);
         }
 
         /// <summary>
diff --git a/Ryujinx.Graphics.Gpu/Image/Texture.cs b/Ryujinx.Graphics.Gpu/Image/Texture.cs
index 5ed9b2a074..352a828d16 100644
--- a/Ryujinx.Graphics.Gpu/Image/Texture.cs
+++ b/Ryujinx.Graphics.Gpu/Image/Texture.cs
@@ -1,4 +1,3 @@
-using Ryujinx.Common;
 using Ryujinx.Common.Logging;
 using Ryujinx.Common.Memory;
 using Ryujinx.Graphics.GAL;
@@ -89,12 +88,6 @@ namespace Ryujinx.Graphics.Gpu.Image
         /// </summary>
         public TextureGroup Group { get; private set; }
 
-        /// <summary>
-        /// Set when a texture has been changed size. This indicates that it may need to be
-        /// changed again when obtained as a sampler.
-        /// </summary>
-        public bool ChangedSize { get; private set; }
-
         /// <summary>
         /// Set when a texture's GPU VA has ever been partially or fully unmapped.
         /// This indicates that the range must be fully checked when matching the texture.
@@ -410,122 +403,6 @@ namespace Ryujinx.Graphics.Gpu.Image
             Group.CreateCopyDependency(contained, FirstLayer + layer, FirstLevel + level, copyTo);
         }
 
-        /// <summary>
-        /// Changes the texture size.
-        /// </summary>
-        /// <remarks>
-        /// This operation may also change the size of all mipmap levels, including from the parent
-        /// and other possible child textures, to ensure that all sizes are consistent.
-        /// </remarks>
-        /// <param name="width">The new texture width</param>
-        /// <param name="height">The new texture height</param>
-        /// <param name="depthOrLayers">The new texture depth (for 3D textures) or layers (for layered textures)</param>
-        public void ChangeSize(int width, int height, int depthOrLayers)
-        {
-            int blockWidth = Info.FormatInfo.BlockWidth;
-            int blockHeight = Info.FormatInfo.BlockHeight;
-
-            width  <<= FirstLevel;
-            height <<= FirstLevel;
-
-            if (Target == Target.Texture3D)
-            {
-                depthOrLayers <<= FirstLevel;
-            }
-            else
-            {
-                depthOrLayers = _viewStorage.Info.DepthOrLayers;
-            }
-
-            _viewStorage.RecreateStorageOrView(width, height, blockWidth, blockHeight, depthOrLayers);
-
-            foreach (Texture view in _viewStorage._views)
-            {
-                int viewWidth  = Math.Max(1, width  >> view.FirstLevel);
-                int viewHeight = Math.Max(1, height >> view.FirstLevel);
-
-                int viewDepthOrLayers;
-
-                if (view.Info.Target == Target.Texture3D)
-                {
-                    viewDepthOrLayers = Math.Max(1, depthOrLayers >> view.FirstLevel);
-                }
-                else
-                {
-                    viewDepthOrLayers = view.Info.DepthOrLayers;
-                }
-
-                view.RecreateStorageOrView(viewWidth, viewHeight, blockWidth, blockHeight, viewDepthOrLayers);
-            }
-        }
-
-        /// <summary>
-        /// Recreates the texture storage (or view, in the case of child textures) of this texture.
-        /// This allows recreating the texture with a new size.
-        /// A copy is automatically performed from the old to the new texture.
-        /// </summary>
-        /// <param name="width">The new texture width</param>
-        /// <param name="height">The new texture height</param>
-        /// <param name="width">The block width related to the given width</param>
-        /// <param name="height">The block height related to the given height</param>
-        /// <param name="depthOrLayers">The new texture depth (for 3D textures) or layers (for layered textures)</param>
-        private void RecreateStorageOrView(int width, int height, int blockWidth, int blockHeight, int depthOrLayers)
-        {
-            RecreateStorageOrView(
-                BitUtils.DivRoundUp(width * Info.FormatInfo.BlockWidth, blockWidth),
-                BitUtils.DivRoundUp(height * Info.FormatInfo.BlockHeight, blockHeight),
-                depthOrLayers);
-        }
-
-        /// <summary>
-        /// Recreates the texture storage (or view, in the case of child textures) of this texture.
-        /// This allows recreating the texture with a new size.
-        /// A copy is automatically performed from the old to the new texture.
-        /// </summary>
-        /// <param name="width">The new texture width</param>
-        /// <param name="height">The new texture height</param>
-        /// <param name="depthOrLayers">The new texture depth (for 3D textures) or layers (for layered textures)</param>
-        private void RecreateStorageOrView(int width, int height, int depthOrLayers)
-        {
-            ChangedSize = true;
-
-            SetInfo(new TextureInfo(
-                Info.GpuAddress,
-                width,
-                height,
-                depthOrLayers,
-                Info.Levels,
-                Info.SamplesInX,
-                Info.SamplesInY,
-                Info.Stride,
-                Info.IsLinear,
-                Info.GobBlocksInY,
-                Info.GobBlocksInZ,
-                Info.GobBlocksInTileX,
-                Info.Target,
-                Info.FormatInfo,
-                Info.DepthStencilMode,
-                Info.SwizzleR,
-                Info.SwizzleG,
-                Info.SwizzleB,
-                Info.SwizzleA));
-
-            TextureCreateInfo createInfo = TextureCache.GetCreateInfo(Info, _context.Capabilities, ScaleFactor);
-
-            if (_viewStorage != this)
-            {
-                ReplaceStorage(_viewStorage.HostTexture.CreateView(createInfo, FirstLayer, FirstLevel));
-            }
-            else
-            {
-                ITexture newStorage = _context.Renderer.CreateTexture(createInfo, ScaleFactor);
-
-                HostTexture.CopyTo(newStorage, 0, 0);
-
-                ReplaceStorage(newStorage);
-            }
-        }
-
         /// <summary>
         /// Registers when a texture has had its data set after being scaled, and
         /// determines if it should be blacklisted from scaling to improve performance.
@@ -1215,7 +1092,9 @@ namespace Ryujinx.Graphics.Gpu.Image
         /// <returns>A value indicating how well this texture matches the given info</returns>
         public TextureMatchQuality IsExactMatch(TextureInfo info, TextureSearchFlags flags)
         {
-            TextureMatchQuality matchQuality = TextureCompatibility.FormatMatches(Info, info, (flags & TextureSearchFlags.ForSampler) != 0, (flags & TextureSearchFlags.ForCopy) != 0);
+            bool forSampler = (flags & TextureSearchFlags.ForSampler) != 0;
+
+            TextureMatchQuality matchQuality = TextureCompatibility.FormatMatches(Info, info, forSampler, (flags & TextureSearchFlags.ForCopy) != 0);
 
             if (matchQuality == TextureMatchQuality.NoMatch)
             {
@@ -1227,12 +1106,12 @@ namespace Ryujinx.Graphics.Gpu.Image
                 return TextureMatchQuality.NoMatch;
             }
 
-            if (!TextureCompatibility.SizeMatches(Info, info, (flags & TextureSearchFlags.Strict) == 0, FirstLevel))
+            if (!TextureCompatibility.SizeMatches(Info, info, forSampler))
             {
                 return TextureMatchQuality.NoMatch;
             }
 
-            if ((flags & TextureSearchFlags.ForSampler) != 0 || (flags & TextureSearchFlags.Strict) != 0)
+            if ((flags & TextureSearchFlags.ForSampler) != 0)
             {
                 if (!TextureCompatibility.SamplerParamsMatches(Info, info))
                 {
@@ -1262,12 +1141,20 @@ namespace Ryujinx.Graphics.Gpu.Image
         /// </summary>
         /// <param name="info">Texture view information</param>
         /// <param name="range">Texture view physical memory ranges</param>
+        /// <param name="exactSize">Indicates if the texture sizes must be exactly equal, or width is allowed to differ</param>
         /// <param name="layerSize">Layer size on the given texture</param>
         /// <param name="caps">Host GPU capabilities</param>
         /// <param name="firstLayer">Texture view initial layer on this texture</param>
         /// <param name="firstLevel">Texture view first mipmap level on this texture</param>
         /// <returns>The level of compatiblilty a view with the given parameters created from this texture has</returns>
-        public TextureViewCompatibility IsViewCompatible(TextureInfo info, MultiRange range, int layerSize, Capabilities caps, out int firstLayer, out int firstLevel)
+        public TextureViewCompatibility IsViewCompatible(
+            TextureInfo info,
+            MultiRange range,
+            bool exactSize,
+            int layerSize,
+            Capabilities caps,
+            out int firstLayer,
+            out int firstLevel)
         {
             TextureViewCompatibility result = TextureViewCompatibility.Full;
 
@@ -1317,7 +1204,7 @@ namespace Ryujinx.Graphics.Gpu.Image
                 return TextureViewCompatibility.LayoutIncompatible;
             }
 
-            result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewSizeMatches(Info, info, firstLevel));
+            result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewSizeMatches(Info, info, exactSize, firstLevel));
             result = TextureCompatibility.PropagateViewCompatibility(result, TextureCompatibility.ViewSubImagesInBounds(Info, info, firstLayer, firstLevel));
 
             return result;
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
index 9802a3dcc1..1d5b1851f5 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureCache.cs
@@ -210,8 +210,8 @@ namespace Ryujinx.Graphics.Gpu.Image
             ulong offset,
             FormatInfo formatInfo,
             bool shouldCreate,
-            bool preferScaling = true,
-            Size? sizeHint = null)
+            bool preferScaling,
+            Size sizeHint)
         {
             int gobBlocksInY = copyTexture.MemoryLayout.UnpackGobBlocksInY();
             int gobBlocksInZ = copyTexture.MemoryLayout.UnpackGobBlocksInZ();
@@ -229,7 +229,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 
             TextureInfo info = new TextureInfo(
                 copyTexture.Address.Pack() + offset,
-                width,
+                GetMinimumWidthInGob(width, sizeHint.Width, formatInfo.BytesPerPixel, copyTexture.LinearLayout),
                 copyTexture.Height,
                 copyTexture.Depth,
                 1,
@@ -255,7 +255,7 @@ namespace Ryujinx.Graphics.Gpu.Image
                 flags |= TextureSearchFlags.NoCreate;
             }
 
-            Texture texture = FindOrCreateTexture(memoryManager, flags, info, 0, sizeHint);
+            Texture texture = FindOrCreateTexture(memoryManager, flags, info, 0);
 
             texture?.SynchronizeMemory();
 
@@ -326,7 +326,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 
             TextureInfo info = new TextureInfo(
                 colorState.Address.Pack(),
-                width,
+                GetMinimumWidthInGob(width, sizeHint.Width, formatInfo.BytesPerPixel, isLinear),
                 colorState.Height,
                 colorState.Depth,
                 1,
@@ -342,7 +342,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 
             int layerSize = !isLinear ? colorState.LayerSize * 4 : 0;
 
-            Texture texture = FindOrCreateTexture(memoryManager, TextureSearchFlags.WithUpscale, info, layerSize, sizeHint);
+            Texture texture = FindOrCreateTexture(memoryManager, TextureSearchFlags.WithUpscale, info, layerSize);
 
             texture?.SynchronizeMemory();
 
@@ -395,7 +395,7 @@ namespace Ryujinx.Graphics.Gpu.Image
 
             TextureInfo info = new TextureInfo(
                 dsState.Address.Pack(),
-                size.Width,
+                GetMinimumWidthInGob(size.Width, sizeHint.Width, formatInfo.BytesPerPixel, false),
                 size.Height,
                 size.Depth,
                 1,
@@ -409,13 +409,41 @@ namespace Ryujinx.Graphics.Gpu.Image
                 target,
                 formatInfo);
 
-            Texture texture = FindOrCreateTexture(memoryManager, TextureSearchFlags.WithUpscale, info, dsState.LayerSize * 4, sizeHint);
+            Texture texture = FindOrCreateTexture(memoryManager, TextureSearchFlags.WithUpscale, info, dsState.LayerSize * 4);
 
             texture?.SynchronizeMemory();
 
             return texture;
         }
 
+        /// <summary>
+        /// For block linear textures, gets the minimum width of the texture
+        /// that would still have the same number of GOBs per row as the original width.
+        /// </summary>
+        /// <param name="width">The possibly aligned texture width</param>
+        /// <param name="minimumWidth">The minimum width that the texture may have without losing data</param>
+        /// <param name="bytesPerPixel">Bytes per pixel of the texture format</param>
+        /// <param name="isLinear">True if the texture is linear, false for block linear</param>
+        /// <returns>The minimum width of the texture with the same amount of GOBs per row</returns>
+        private static int GetMinimumWidthInGob(int width, int minimumWidth, int bytesPerPixel, bool isLinear)
+        {
+            if (isLinear || (uint)minimumWidth >= (uint)width)
+            {
+                return width;
+            }
+
+            // Calculate the minimum possible that would not cause data loss
+            // and would be still within the same GOB (aligned size would be the same).
+            // This is useful for render and copy operations, where we don't know the
+            // exact width of the texture, but it doesn't matter, as long the texture is
+            // at least as large as the region being rendered or copied.
+
+            int alignment = 64 / bytesPerPixel;
+            int widthAligned = BitUtils.AlignUp(width, alignment);
+
+            return Math.Clamp(widthAligned - alignment + 1, minimumWidth, widthAligned);
+        }
+
         /// <summary>
         /// Tries to find an existing texture, or create a new one if not found.
         /// </summary>
@@ -423,7 +451,6 @@ namespace Ryujinx.Graphics.Gpu.Image
         /// <param name="flags">The texture search flags, defines texture comparison rules</param>
         /// <param name="info">Texture information of the texture to be found or created</param>
         /// <param name="layerSize">Size in bytes of a single texture layer</param>
-        /// <param name="sizeHint">A hint indicating the minimum used size for the texture</param>
         /// <param name="range">Optional ranges of physical memory where the texture data is located</param>
         /// <returns>The texture</returns>
         public Texture FindOrCreateTexture(
@@ -431,7 +458,6 @@ namespace Ryujinx.Graphics.Gpu.Image
             TextureSearchFlags flags,
             TextureInfo info,
             int layerSize = 0,
-            Size? sizeHint = null,
             MultiRange? range = null)
         {
             bool isSamplerTexture = (flags & TextureSearchFlags.ForSampler) != 0;
@@ -512,8 +538,6 @@ namespace Ryujinx.Graphics.Gpu.Image
 
             if (texture != null)
             {
-                ChangeSizeIfNeeded(info, texture, isSamplerTexture, sizeHint);
-
                 texture.SynchronizeMemory();
 
                 return texture;
@@ -568,6 +592,7 @@ namespace Ryujinx.Graphics.Gpu.Image
                 TextureViewCompatibility overlapCompatibility = overlap.IsViewCompatible(
                     info,
                     range.Value,
+                    isSamplerTexture,
                     sizeInfo.LayerSize,
                     _context.Capabilities,
                     out int firstLayer,
@@ -598,17 +623,15 @@ namespace Ryujinx.Graphics.Gpu.Image
 
                 if (oInfo.Compatibility == TextureViewCompatibility.Full)
                 {
-                    TextureInfo adjInfo = AdjustSizes(overlap, info, oInfo.FirstLevel);
-
                     if (!isSamplerTexture)
                     {
-                        info = adjInfo;
+                        // If this is not a sampler texture, the size might be different from the requested size,
+                        // so we need to make sure the texture information has the correct size for this base texture,
+                        // before creating the view.
+                        info = info.CreateInfoForLevelView(overlap, oInfo.FirstLevel);
                     }
 
-                    texture = overlap.CreateView(adjInfo, sizeInfo, range.Value, oInfo.FirstLayer, oInfo.FirstLevel);
-
-                    ChangeSizeIfNeeded(info, texture, isSamplerTexture, sizeHint);
-
+                    texture = overlap.CreateView(info, sizeInfo, range.Value, oInfo.FirstLayer, oInfo.FirstLevel);
                     texture.SynchronizeMemory();
                     break;
                 }
@@ -682,6 +705,7 @@ namespace Ryujinx.Graphics.Gpu.Image
                     TextureViewCompatibility compatibility = texture.IsViewCompatible(
                         overlap.Info,
                         overlap.Range,
+                        exactSize: true,
                         overlap.LayerSize,
                         _context.Capabilities,
                         out int firstLayer,
@@ -792,7 +816,11 @@ namespace Ryujinx.Graphics.Gpu.Image
                         continue;
                     }
 
-                    TextureInfo overlapInfo = AdjustSizes(texture, overlap.Info, oInfo.FirstLevel);
+                    // Note: If we allow different sizes for those overlaps,
+                    // we need to make sure that the "info" has the correct size for the parent texture here.
+                    // Since this is not allowed right now, we don't need to do it.
+
+                    TextureInfo overlapInfo = overlap.Info;
 
                     if (texture.ScaleFactor != overlap.ScaleFactor)
                     {
@@ -856,44 +884,6 @@ namespace Ryujinx.Graphics.Gpu.Image
             return texture;
         }
 
-        /// <summary>
-        /// Changes a texture's size to match the desired size for samplers,
-        /// or increases a texture's size to fit the region indicated by a size hint.
-        /// </summary>
-        /// <param name="info">The desired texture info</param>
-        /// <param name="texture">The texture to resize</param>
-        /// <param name="isSamplerTexture">True if the texture will be used for a sampler, false otherwise</param>
-        /// <param name="sizeHint">A hint indicating the minimum used size for the texture</param>
-        private void ChangeSizeIfNeeded(TextureInfo info, Texture texture, bool isSamplerTexture, Size? sizeHint)
-        {
-            if (isSamplerTexture)
-            {
-                // If this is used for sampling, the size must match,
-                // otherwise the shader would sample garbage data.
-                // To fix that, we create a new texture with the correct
-                // size, and copy the data from the old one to the new one.
-
-                if (!TextureCompatibility.SizeMatches(texture.Info, info))
-                {
-                    texture.ChangeSize(info.Width, info.Height, info.DepthOrLayers);
-                }
-            }
-            else if (sizeHint != null)
-            {
-                // A size hint indicates that data will be used within that range, at least.
-                // If the texture is smaller than the size hint, it must be enlarged to meet it.
-                // The maximum size is provided by the requested info, which generally has an aligned size.
-
-                int width = Math.Max(texture.Info.Width, Math.Min(sizeHint.Value.Width, info.Width));
-                int height = Math.Max(texture.Info.Height, Math.Min(sizeHint.Value.Height, info.Height));
-
-                if (texture.Info.Width != width || texture.Info.Height != height)
-                {
-                    texture.ChangeSize(width, height, info.DepthOrLayers);
-                }
-            }
-        }
-
         /// <summary>
         /// Attempt to find a texture on the short duration cache.
         /// </summary>
@@ -1000,92 +990,6 @@ namespace Ryujinx.Graphics.Gpu.Image
             }
         }
 
-        /// <summary>
-        /// Adjusts the size of the texture information for a given mipmap level,
-        /// based on the size of a parent texture.
-        /// </summary>
-        /// <param name="parent">The parent texture</param>
-        /// <param name="info">The texture information to be adjusted</param>
-        /// <param name="firstLevel">The first level of the texture view</param>
-        /// <returns>The adjusted texture information with the new size</returns>
-        private static TextureInfo AdjustSizes(Texture parent, TextureInfo info, int firstLevel)
-        {
-            // When the texture is used as view of another texture, we must
-            // ensure that the sizes are valid, otherwise data uploads would fail
-            // (and the size wouldn't match the real size used on the host API).
-            // Given a parent texture from where the view is created, we have the
-            // following rules:
-            // - The view size must be equal to the parent size, divided by (2 ^ l),
-            // where l is the first mipmap level of the view. The division result must
-            // be rounded down, and the result must be clamped to 1.
-            // - If the parent format is compressed, and the view format isn't, the
-            // view size is calculated as above, but the width and height of the
-            // view must be also divided by the compressed format block width and height.
-            // - If the parent format is not compressed, and the view is, the view
-            // size is calculated as described on the first point, but the width and height
-            // of the view must be also multiplied by the block width and height.
-            int width  = Math.Max(1, parent.Info.Width  >> firstLevel);
-            int height = Math.Max(1, parent.Info.Height >> firstLevel);
-
-            if (parent.Info.FormatInfo.IsCompressed && !info.FormatInfo.IsCompressed)
-            {
-                width  = BitUtils.DivRoundUp(width,  parent.Info.FormatInfo.BlockWidth);
-                height = BitUtils.DivRoundUp(height, parent.Info.FormatInfo.BlockHeight);
-            }
-            else if (!parent.Info.FormatInfo.IsCompressed && info.FormatInfo.IsCompressed)
-            {
-                width  *= info.FormatInfo.BlockWidth;
-                height *= info.FormatInfo.BlockHeight;
-            }
-
-            int depthOrLayers;
-
-            if (info.Target == Target.Texture3D)
-            {
-                depthOrLayers = Math.Max(1, parent.Info.DepthOrLayers >> firstLevel);
-            }
-            else
-            {
-                depthOrLayers = info.DepthOrLayers;
-            }
-
-            // 2D and 2D multisample textures are not considered compatible.
-            // This specific case is required for copies, where the source texture might be multisample.
-            // In this case, we inherit the parent texture multisample state.
-            Target target = info.Target;
-            int samplesInX = info.SamplesInX;
-            int samplesInY = info.SamplesInY;
-
-            if (target == Target.Texture2D && parent.Target == Target.Texture2DMultisample)
-            {
-                target = Target.Texture2DMultisample;
-                samplesInX = parent.Info.SamplesInX;
-                samplesInY = parent.Info.SamplesInY;
-            }
-
-            return new TextureInfo(
-                info.GpuAddress,
-                width,
-                height,
-                depthOrLayers,
-                info.Levels,
-                samplesInX,
-                samplesInY,
-                info.Stride,
-                info.IsLinear,
-                info.GobBlocksInY,
-                info.GobBlocksInZ,
-                info.GobBlocksInTileX,
-                target,
-                info.FormatInfo,
-                info.DepthStencilMode,
-                info.SwizzleR,
-                info.SwizzleG,
-                info.SwizzleB,
-                info.SwizzleA);
-        }
-
-
         /// <summary>
         /// Gets a texture creation information from texture information.
         /// This can be used to create new host textures.
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs b/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs
index 7ec4c7ac2b..e8061951be 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureCompatibility.cs
@@ -380,42 +380,37 @@ namespace Ryujinx.Graphics.Gpu.Image
         /// </summary>
         /// <param name="lhs">Texture information of the texture view</param>
         /// <param name="rhs">Texture information of the texture view to match against</param>
+        /// <param name="exact">Indicates if the sizes must be exactly equal</param>
         /// <param name="level">Mipmap level of the texture view in relation to this texture</param>
         /// <returns>The view compatibility level of the view sizes</returns>
-        public static TextureViewCompatibility ViewSizeMatches(TextureInfo lhs, TextureInfo rhs, int level)
+        public static TextureViewCompatibility ViewSizeMatches(TextureInfo lhs, TextureInfo rhs, bool exact, int level)
         {
-            Size size = GetAlignedSize(lhs, level);
+            Size lhsAlignedSize = GetAlignedSize(lhs, level);
+            Size rhsAlignedSize = GetAlignedSize(rhs);
 
-            Size otherSize = GetAlignedSize(rhs);
+            Size lhsSize = GetSizeInBlocks(lhs, level);
+            Size rhsSize = GetSizeInBlocks(rhs);
 
             TextureViewCompatibility result = TextureViewCompatibility.Full;
 
             // For copies, we can copy a subset of the 3D texture slices,
             // so the depth may be different in this case.
-            if (rhs.Target == Target.Texture3D && size.Depth != otherSize.Depth)
+            if (rhs.Target == Target.Texture3D && lhsSize.Depth != rhsSize.Depth)
             {
                 result = TextureViewCompatibility.CopyOnly;
             }
 
-            if (size.Width == otherSize.Width && size.Height == otherSize.Height)
+            // Some APIs align the width for copy and render target textures,
+            // so the width may not match in this case for different uses of the same texture.
+            // To account for this, we compare the aligned width here.
+            // We expect height to always match exactly, if the texture is the same.
+            if (lhsAlignedSize.Width == rhsAlignedSize.Width && lhsSize.Height == rhsSize.Height)
             {
-                if (level > 0 && result == TextureViewCompatibility.Full)
-                {
-                    // A resize should not change the aligned size of the largest mip.
-                    // If it would, then create a copy dependency rather than a full view.
-
-                    Size mip0SizeLhs = GetAlignedSize(lhs);
-                    Size mip0SizeRhs = GetLargestAlignedSize(rhs, level);
-
-                    if (mip0SizeLhs.Width != mip0SizeRhs.Width || mip0SizeLhs.Height != mip0SizeRhs.Height)
-                    {
-                        result = TextureViewCompatibility.CopyOnly;
-                    }
-                }
-
-                return result;
+                return (exact && lhsSize.Width != rhsSize.Width) || lhsSize.Width < rhsSize.Width
+                    ? TextureViewCompatibility.CopyOnly
+                    : result;
             }
-            else if (lhs.IsLinear && rhs.IsLinear)
+            else if (lhs.IsLinear && rhs.IsLinear && lhsSize.Height == rhsSize.Height)
             {
                 // Copy between linear textures with matching stride.
                 int stride = BitUtils.AlignUp(Math.Max(1, lhs.Stride >> level), Constants.StrideAlignment);
@@ -454,57 +449,33 @@ namespace Ryujinx.Graphics.Gpu.Image
         /// </summary>
         /// <param name="lhs">Texture information to compare</param>
         /// <param name="rhs">Texture information to compare with</param>
-        /// <returns>True if the size matches, false otherwise</returns>
-        public static bool SizeMatches(TextureInfo lhs, TextureInfo rhs)
-        {
-            return SizeMatches(lhs, rhs, alignSizes: false);
-        }
-
-        /// <summary>
-        /// Checks if the texture sizes of the supplied texture informations match the given level
-        /// </summary>
-        /// <param name="lhs">Texture information to compare</param>
-        /// <param name="rhs">Texture information to compare with</param>
-        /// <param name="level">Mipmap level of this texture to compare with</param>
-        /// <returns>True if the size matches with the level, false otherwise</returns>
-        public static bool SizeMatches(TextureInfo lhs, TextureInfo rhs, int level)
-        {
-            return Math.Max(1, lhs.Width >> level)      == rhs.Width &&
-                   Math.Max(1, lhs.Height >> level)     == rhs.Height &&
-                   Math.Max(1, lhs.GetDepth() >> level) == rhs.GetDepth();
-        }
-
-        /// <summary>
-        /// Checks if the texture sizes of the supplied texture informations match.
-        /// </summary>
-        /// <param name="lhs">Texture information to compare</param>
-        /// <param name="rhs">Texture information to compare with</param>
-        /// <param name="alignSizes">True to align the sizes according to the texture layout for comparison</param>
-        /// <param name="lhsLevel">Mip level of the lhs texture. Aligned sizes are compared for the largest mip</param>
+        /// <param name="exact">Indicates if the size must be exactly equal between the textures, or if <paramref name="rhs"/> is allowed to be larger</param>
         /// <returns>True if the sizes matches, false otherwise</returns>
-        public static bool SizeMatches(TextureInfo lhs, TextureInfo rhs, bool alignSizes, int lhsLevel = 0)
+        public static bool SizeMatches(TextureInfo lhs, TextureInfo rhs, bool exact)
         {
             if (lhs.GetLayers() != rhs.GetLayers())
             {
                 return false;
             }
 
-            bool isTextureBuffer = lhs.Target == Target.TextureBuffer || rhs.Target == Target.TextureBuffer;
+            Size lhsSize = GetSizeInBlocks(lhs);
+            Size rhsSize = GetSizeInBlocks(rhs);
 
-            if (alignSizes && !isTextureBuffer)
+            if (exact || lhs.IsLinear || rhs.IsLinear)
             {
-                Size size0 = GetLargestAlignedSize(lhs, lhsLevel);
-                Size size1 = GetLargestAlignedSize(rhs, lhsLevel);
-
-                return size0.Width  == size1.Width &&
-                       size0.Height == size1.Height &&
-                       size0.Depth  == size1.Depth;
+                return lhsSize.Width == rhsSize.Width &&
+                       lhsSize.Height == rhsSize.Height &&
+                       lhsSize.Depth == rhsSize.Depth;
             }
             else
             {
-                return lhs.Width      == rhs.Width &&
-                       lhs.Height     == rhs.Height &&
-                       lhs.GetDepth() == rhs.GetDepth();
+                Size lhsAlignedSize = GetAlignedSize(lhs);
+                Size rhsAlignedSize = GetAlignedSize(rhs);
+
+                return lhsAlignedSize.Width == rhsAlignedSize.Width &&
+                       lhsSize.Width >= rhsSize.Width &&
+                       lhsSize.Height == rhsSize.Height &&
+                       lhsSize.Depth == rhsSize.Depth;
             }
         }
 
@@ -543,22 +514,6 @@ namespace Ryujinx.Graphics.Gpu.Image
             }
         }
 
-        /// <summary>
-        /// Gets the aligned sizes of the specified texture information, shifted to the largest mip from a given level.
-        /// The alignment depends on the texture layout and format bytes per pixel.
-        /// </summary>
-        /// <param name="info">Texture information to calculate the aligned size from</param>
-        /// <param name="level">Mipmap level for texture views. Shifts the aligned size to represent the largest mip level</param>
-        /// <returns>The aligned texture size of the largest mip level</returns>
-        public static Size GetLargestAlignedSize(TextureInfo info, int level)
-        {
-            int width = info.Width << level;
-            int height = info.Height << level;
-            int depth = info.GetDepth() << level;
-
-            return GetAlignedSize(info, width, height, depth);
-        }
-
         /// <summary>
         /// Gets the aligned sizes of the specified texture information.
         /// The alignment depends on the texture layout and format bytes per pixel.
@@ -575,6 +530,25 @@ namespace Ryujinx.Graphics.Gpu.Image
             return GetAlignedSize(info, width, height, depth);
         }
 
+        /// <summary>
+        /// Gets the size in blocks for the given texture information.
+        /// For non-compressed formats, that's the same as the regular size.
+        /// </summary>
+        /// <param name="info">Texture information to calculate the aligned size from</param>
+        /// <param name="level">Mipmap level for texture views</param>
+        /// <returns>The texture size in blocks</returns>
+        public static Size GetSizeInBlocks(TextureInfo info, int level = 0)
+        {
+            int width = Math.Max(1, info.Width >> level);
+            int height = Math.Max(1, info.Height >> level);
+            int depth = Math.Max(1, info.GetDepth() >> level);
+
+            return new Size(
+                BitUtils.DivRoundUp(width, info.FormatInfo.BlockWidth),
+                BitUtils.DivRoundUp(height, info.FormatInfo.BlockHeight),
+                depth);
+        }
+
         /// <summary>
         /// Check if it's possible to create a view with the layout of the second texture information from the first.
         /// The layout information is composed of the Stride for linear textures, or GOB block size
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureInfo.cs b/Ryujinx.Graphics.Gpu/Image/TextureInfo.cs
index 65cc698b0f..a7ee12bccd 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureInfo.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureInfo.cs
@@ -1,5 +1,7 @@
+using Ryujinx.Common;
 using Ryujinx.Graphics.GAL;
 using Ryujinx.Graphics.Texture;
+using System;
 
 namespace Ryujinx.Graphics.Gpu.Image
 {
@@ -292,5 +294,88 @@ namespace Ryujinx.Graphics.Gpu.Image
                     layerSize);
             }
         }
+
+        /// <summary>
+        /// Creates texture information for a given mipmap level of the specified parent texture and this information.
+        /// </summary>
+        /// <param name="parent">The parent texture</param>
+        /// <param name="firstLevel">The first level of the texture view</param>
+        /// <returns>The adjusted texture information with the new size</returns>
+        public TextureInfo CreateInfoForLevelView(Texture parent, int firstLevel)
+        {
+            // When the texture is used as view of another texture, we must
+            // ensure that the sizes are valid, otherwise data uploads would fail
+            // (and the size wouldn't match the real size used on the host API).
+            // Given a parent texture from where the view is created, we have the
+            // following rules:
+            // - The view size must be equal to the parent size, divided by (2 ^ l),
+            // where l is the first mipmap level of the view. The division result must
+            // be rounded down, and the result must be clamped to 1.
+            // - If the parent format is compressed, and the view format isn't, the
+            // view size is calculated as above, but the width and height of the
+            // view must be also divided by the compressed format block width and height.
+            // - If the parent format is not compressed, and the view is, the view
+            // size is calculated as described on the first point, but the width and height
+            // of the view must be also multiplied by the block width and height.
+            int width  = Math.Max(1, parent.Info.Width  >> firstLevel);
+            int height = Math.Max(1, parent.Info.Height >> firstLevel);
+
+            if (parent.Info.FormatInfo.IsCompressed && !FormatInfo.IsCompressed)
+            {
+                width  = BitUtils.DivRoundUp(width,  parent.Info.FormatInfo.BlockWidth);
+                height = BitUtils.DivRoundUp(height, parent.Info.FormatInfo.BlockHeight);
+            }
+            else if (!parent.Info.FormatInfo.IsCompressed && FormatInfo.IsCompressed)
+            {
+                width  *= FormatInfo.BlockWidth;
+                height *= FormatInfo.BlockHeight;
+            }
+
+            int depthOrLayers;
+
+            if (Target == Target.Texture3D)
+            {
+                depthOrLayers = Math.Max(1, parent.Info.DepthOrLayers >> firstLevel);
+            }
+            else
+            {
+                depthOrLayers = DepthOrLayers;
+            }
+
+            // 2D and 2D multisample textures are not considered compatible.
+            // This specific case is required for copies, where the source texture might be multisample.
+            // In this case, we inherit the parent texture multisample state.
+            Target target = Target;
+            int samplesInX = SamplesInX;
+            int samplesInY = SamplesInY;
+
+            if (target == Target.Texture2D && parent.Target == Target.Texture2DMultisample)
+            {
+                target = Target.Texture2DMultisample;
+                samplesInX = parent.Info.SamplesInX;
+                samplesInY = parent.Info.SamplesInY;
+            }
+
+            return new TextureInfo(
+                GpuAddress,
+                width,
+                height,
+                depthOrLayers,
+                Levels,
+                samplesInX,
+                samplesInY,
+                Stride,
+                IsLinear,
+                GobBlocksInY,
+                GobBlocksInZ,
+                GobBlocksInTileX,
+                target,
+                FormatInfo,
+                DepthStencilMode,
+                SwizzleR,
+                SwizzleG,
+                SwizzleB,
+                SwizzleA);
+        }
     }
 }
\ No newline at end of file
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
index 083de64c55..266f62856b 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureManager.cs
@@ -437,22 +437,6 @@ namespace Ryujinx.Graphics.Gpu.Image
             }
         }
 
-        /// <summary>
-        /// Update host framebuffer attachments based on currently bound render target buffers.
-        /// </summary>
-        /// <remarks>
-        /// All attachments other than <paramref name="index"/> will be unbound.
-        /// </remarks>
-        /// <param name="index">Index of the render target color to be updated</param>
-        public void UpdateRenderTarget(int index)
-        {
-            new Span<ITexture>(_rtHostColors).Fill(null);
-            _rtHostColors[index] = _rtColors[index]?.HostTexture;
-            _rtHostDs = null;
-
-            _context.Renderer.Pipeline.SetRenderTargets(_rtHostColors, null);
-        }
-
         /// <summary>
         /// Update host framebuffer attachments based on currently bound render target buffers.
         /// </summary>
diff --git a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
index fc99fc9977..0348ca014b 100644
--- a/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TexturePool.cs
@@ -77,22 +77,7 @@ namespace Ryujinx.Graphics.Gpu.Image
             }
             else
             {
-                if (texture.ChangedSize)
-                {
-                    // Texture changed size at one point - it may be a different size than the sampler expects.
-                    // This can be triggered when the size is changed by a size hint on copy or draw, but the texture has been sampled before.
-
-                    int baseLevel = descriptor.UnpackBaseLevel();
-                    int width = Math.Max(1, descriptor.UnpackWidth() >> baseLevel);
-                    int height = Math.Max(1, descriptor.UnpackHeight() >> baseLevel);
-
-                    if (texture.Info.Width != width || texture.Info.Height != height)
-                    {
-                        texture.ChangeSize(width, height, texture.Info.DepthOrLayers);
-                    }
-                }
-
-                // Memory is automatically synchronized on texture creation.
+                // On the path above (texture not yet in the pool), memory is automatically synchronized on texture creation.
                 texture.SynchronizeMemory();
             }
 
diff --git a/Ryujinx.Graphics.Gpu/Image/TextureSearchFlags.cs b/Ryujinx.Graphics.Gpu/Image/TextureSearchFlags.cs
index aea7b167e6..890bf1736f 100644
--- a/Ryujinx.Graphics.Gpu/Image/TextureSearchFlags.cs
+++ b/Ryujinx.Graphics.Gpu/Image/TextureSearchFlags.cs
@@ -9,7 +9,6 @@ namespace Ryujinx.Graphics.Gpu.Image
     enum TextureSearchFlags
     {
         None        = 0,
-        Strict      = 1 << 0,
         ForSampler  = 1 << 1,
         ForCopy     = 1 << 2,
         WithUpscale = 1 << 3,
diff --git a/Ryujinx.Graphics.Gpu/Window.cs b/Ryujinx.Graphics.Gpu/Window.cs
index 90f8e40f92..06d0fddf49 100644
--- a/Ryujinx.Graphics.Gpu/Window.cs
+++ b/Ryujinx.Graphics.Gpu/Window.cs
@@ -202,7 +202,7 @@ namespace Ryujinx.Graphics.Gpu
             {
                 pt.AcquireCallback(_context, pt.UserObj);
 
-                Texture texture = pt.Cache.FindOrCreateTexture(null, TextureSearchFlags.WithUpscale, pt.Info, 0, null, pt.Range);
+                Texture texture = pt.Cache.FindOrCreateTexture(null, TextureSearchFlags.WithUpscale, pt.Info, 0, pt.Range);
 
                 pt.Cache.Tick();