diff --git a/Ryujinx.Graphics.Gpu/Image/Texture.cs b/Ryujinx.Graphics.Gpu/Image/Texture.cs index 0a578c924..c5c7a09bd 100644 --- a/Ryujinx.Graphics.Gpu/Image/Texture.cs +++ b/Ryujinx.Graphics.Gpu/Image/Texture.cs @@ -1229,16 +1229,18 @@ namespace Ryujinx.Graphics.Gpu.Image if (_arrayViewTexture == null && IsSameDimensionsTarget(target)) { + FormatInfo formatInfo = TextureCompatibility.ToHostCompatibleFormat(Info, _context.Capabilities); + TextureCreateInfo createInfo = new TextureCreateInfo( Info.Width, Info.Height, target == Target.CubemapArray ? 6 : 1, Info.Levels, Info.Samples, - Info.FormatInfo.BlockWidth, - Info.FormatInfo.BlockHeight, - Info.FormatInfo.BytesPerPixel, - Info.FormatInfo.Format, + formatInfo.BlockWidth, + formatInfo.BlockHeight, + formatInfo.BytesPerPixel, + formatInfo.Format, Info.DepthStencilMode, target, Info.SwizzleR, diff --git a/Ryujinx.Graphics.Texture/BCnDecoder.cs b/Ryujinx.Graphics.Texture/BCnDecoder.cs index 053f6a735..b21fa4d10 100644 --- a/Ryujinx.Graphics.Texture/BCnDecoder.cs +++ b/Ryujinx.Graphics.Texture/BCnDecoder.cs @@ -298,9 +298,12 @@ namespace Ryujinx.Graphics.Texture for (int l = 0; l < levels; l++) { - size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers; + size += BitUtils.AlignUp(Math.Max(1, width >> l), 4) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers; } + // Backends currently expect a stride alignment of 4 bytes, so output width must be aligned. + int alignedWidth = BitUtils.AlignUp(width, 4); + byte[] output = new byte[size]; Span outputSpan = new Span(output); @@ -331,14 +334,14 @@ namespace Ryujinx.Graphics.Texture { int baseY = y * BlockHeight; int copyHeight = Math.Min(BlockHeight, height - baseY); - int lineBaseOOffs = imageBaseOOffs + baseY * width; + int lineBaseOOffs = imageBaseOOffs + baseY * alignedWidth; if (copyHeight == 4) { outputLine0 = MemoryMarshal.Cast(outputSpan.Slice(lineBaseOOffs)); - outputLine1 = MemoryMarshal.Cast(outputSpan.Slice(lineBaseOOffs + width)); - outputLine2 = MemoryMarshal.Cast(outputSpan.Slice(lineBaseOOffs + width * 2)); - outputLine3 = MemoryMarshal.Cast(outputSpan.Slice(lineBaseOOffs + width * 3)); + outputLine1 = MemoryMarshal.Cast(outputSpan.Slice(lineBaseOOffs + alignedWidth)); + outputLine2 = MemoryMarshal.Cast(outputSpan.Slice(lineBaseOOffs + alignedWidth * 2)); + outputLine3 = MemoryMarshal.Cast(outputSpan.Slice(lineBaseOOffs + alignedWidth * 3)); } for (int x = 0; x < w; x++) @@ -375,7 +378,7 @@ namespace Ryujinx.Graphics.Texture for (int tY = 0; tY < copyHeight; tY++) { - tile.Slice(tY * 4, copyWidth).CopyTo(outputSpan.Slice(pixelBaseOOffs + width * tY, copyWidth)); + tile.Slice(tY * 4, copyWidth).CopyTo(outputSpan.Slice(pixelBaseOOffs + alignedWidth * tY, copyWidth)); } } @@ -383,13 +386,15 @@ namespace Ryujinx.Graphics.Texture } } - imageBaseOOffs += width * height; + imageBaseOOffs += alignedWidth * height; } } width = Math.Max(1, width >> 1); height = Math.Max(1, height >> 1); depth = Math.Max(1, depth >> 1); + + alignedWidth = BitUtils.AlignUp(width, 4); } return output; @@ -401,9 +406,12 @@ namespace Ryujinx.Graphics.Texture for (int l = 0; l < levels; l++) { - size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 2; + size += BitUtils.AlignUp(Math.Max(1, width >> l), 2) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 2; } + // Backends currently expect a stride alignment of 4 bytes, so output width must be aligned. + int alignedWidth = BitUtils.AlignUp(width, 2); + byte[] output = new byte[size]; ReadOnlySpan data64 = MemoryMarshal.Cast(data); @@ -438,14 +446,14 @@ namespace Ryujinx.Graphics.Texture { int baseY = y * BlockHeight; int copyHeight = Math.Min(BlockHeight, height - baseY); - int lineBaseOOffs = imageBaseOOffs + baseY * width; + int lineBaseOOffs = imageBaseOOffs + baseY * alignedWidth; if (copyHeight == 4) { outputLine0 = MemoryMarshal.Cast(outputAsUshort.Slice(lineBaseOOffs)); - outputLine1 = MemoryMarshal.Cast(outputAsUshort.Slice(lineBaseOOffs + width)); - outputLine2 = MemoryMarshal.Cast(outputAsUshort.Slice(lineBaseOOffs + width * 2)); - outputLine3 = MemoryMarshal.Cast(outputAsUshort.Slice(lineBaseOOffs + width * 3)); + outputLine1 = MemoryMarshal.Cast(outputAsUshort.Slice(lineBaseOOffs + alignedWidth)); + outputLine2 = MemoryMarshal.Cast(outputAsUshort.Slice(lineBaseOOffs + alignedWidth * 2)); + outputLine3 = MemoryMarshal.Cast(outputAsUshort.Slice(lineBaseOOffs + alignedWidth * 3)); } for (int x = 0; x < w; x++) @@ -488,7 +496,7 @@ namespace Ryujinx.Graphics.Texture for (int tY = 0; tY < copyHeight; tY++) { - int line = pixelBaseOOffs + width * tY; + int line = pixelBaseOOffs + alignedWidth * tY; for (int tX = 0; tX < copyWidth; tX++) { @@ -503,13 +511,15 @@ namespace Ryujinx.Graphics.Texture } } - imageBaseOOffs += width * height; + imageBaseOOffs += alignedWidth * height; } } width = Math.Max(1, width >> 1); height = Math.Max(1, height >> 1); depth = Math.Max(1, depth >> 1); + + alignedWidth = BitUtils.AlignUp(width, 2); } return output;