aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics.Texture/BCnDecoder.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics.Texture/BCnDecoder.cs')
-rw-r--r--Ryujinx.Graphics.Texture/BCnDecoder.cs114
1 files changed, 100 insertions, 14 deletions
diff --git a/Ryujinx.Graphics.Texture/BCnDecoder.cs b/Ryujinx.Graphics.Texture/BCnDecoder.cs
index b840cac8..b21fa4d1 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<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,7 +511,85 @@ 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;
+ }
+
+ public static byte[] DecodeBC6(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers, bool signed)
+ {
+ int size = 0;
+
+ for (int l = 0; l < levels; l++)
+ {
+ size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 8;
+ }
+
+ byte[] output = new byte[size];
+
+ int inputOffset = 0;
+ int outputOffset = 0;
+
+ for (int l = 0; l < levels; l++)
+ {
+ int w = BitUtils.DivRoundUp(width, BlockWidth);
+ int h = BitUtils.DivRoundUp(height, BlockHeight);
+
+ for (int l2 = 0; l2 < layers; l2++)
+ {
+ for (int z = 0; z < depth; z++)
+ {
+ BC6Decoder.Decode(output.AsSpan().Slice(outputOffset), data.Slice(inputOffset), width, height, signed);
+
+ inputOffset += w * h * 16;
+ outputOffset += width * height * 8;
+ }
+ }
+
+ width = Math.Max(1, width >> 1);
+ height = Math.Max(1, height >> 1);
+ depth = Math.Max(1, depth >> 1);
+ }
+
+ return output;
+ }
+
+ public static byte[] DecodeBC7(ReadOnlySpan<byte> data, int width, int height, int depth, int levels, int layers)
+ {
+ int size = 0;
+
+ for (int l = 0; l < levels; l++)
+ {
+ size += Math.Max(1, width >> l) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 4;
+ }
+
+ byte[] output = new byte[size];
+
+ int inputOffset = 0;
+ int outputOffset = 0;
+
+ for (int l = 0; l < levels; l++)
+ {
+ int w = BitUtils.DivRoundUp(width, BlockWidth);
+ int h = BitUtils.DivRoundUp(height, BlockHeight);
+
+ for (int l2 = 0; l2 < layers; l2++)
+ {
+ for (int z = 0; z < depth; z++)
+ {
+ BC7Decoder.Decode(output.AsSpan().Slice(outputOffset), data.Slice(inputOffset), width, height);
+
+ inputOffset += w * h * 16;
+ outputOffset += width * height * 4;
}
}