Fix BCn 4/5 conversion, GetTextureTarget

BCn 4/5 could generate invalid data when a line's size in bytes was not divisible by 4, which both backends expect.

GetTextureTarget was not creating a view with the replacement format.
This commit is contained in:
riperiperi 2022-05-22 16:45:18 +01:00
parent 782a0c4e93
commit 6ba93addf7
2 changed files with 30 additions and 18 deletions

View file

@ -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,

View file

@ -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<byte> outputSpan = new Span<byte>(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<byte, uint>(outputSpan.Slice(lineBaseOOffs));
outputLine1 = MemoryMarshal.Cast<byte, uint>(outputSpan.Slice(lineBaseOOffs + width));
outputLine2 = MemoryMarshal.Cast<byte, uint>(outputSpan.Slice(lineBaseOOffs + width * 2));
outputLine3 = MemoryMarshal.Cast<byte, uint>(outputSpan.Slice(lineBaseOOffs + width * 3));
outputLine1 = MemoryMarshal.Cast<byte, uint>(outputSpan.Slice(lineBaseOOffs + alignedWidth));
outputLine2 = MemoryMarshal.Cast<byte, uint>(outputSpan.Slice(lineBaseOOffs + alignedWidth * 2));
outputLine3 = MemoryMarshal.Cast<byte, uint>(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<ulong> data64 = MemoryMarshal.Cast<byte, ulong>(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<ushort, ulong>(outputAsUshort.Slice(lineBaseOOffs));
outputLine1 = MemoryMarshal.Cast<ushort, ulong>(outputAsUshort.Slice(lineBaseOOffs + width));
outputLine2 = MemoryMarshal.Cast<ushort, ulong>(outputAsUshort.Slice(lineBaseOOffs + width * 2));
outputLine3 = MemoryMarshal.Cast<ushort, ulong>(outputAsUshort.Slice(lineBaseOOffs + width * 3));
outputLine1 = MemoryMarshal.Cast<ushort, ulong>(outputAsUshort.Slice(lineBaseOOffs + alignedWidth));
outputLine2 = MemoryMarshal.Cast<ushort, ulong>(outputAsUshort.Slice(lineBaseOOffs + alignedWidth * 2));
outputLine3 = MemoryMarshal.Cast<ushort, ulong>(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;