aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs')
-rw-r--r--Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs165
1 files changed, 146 insertions, 19 deletions
diff --git a/Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs b/Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs
index 9451291e..1be06442 100644
--- a/Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs
+++ b/Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs
@@ -1,51 +1,178 @@
+using Ryujinx.Common;
using System;
namespace Ryujinx.Graphics.Texture
{
class BlockLinearSwizzle : ISwizzle
{
+ private const int GobWidth = 64;
+ private const int GobHeight = 8;
+
+ private const int GobSize = GobWidth * GobHeight;
+
+ private int TexWidth;
+ private int TexHeight;
+ private int TexDepth;
+ private int TexGobBlockHeight;
+ private int TexGobBlockDepth;
+ private int TexBpp;
+
+ private int BhMask;
+ private int BdMask;
+
private int BhShift;
+ private int BdShift;
private int BppShift;
- private int BhMask;
private int XShift;
- private int GobStride;
- public BlockLinearSwizzle(int Width, int Bpp, int BlockHeight = 16)
+ private int RobSize;
+ private int SliceSize;
+
+ private int BaseOffset;
+
+ public BlockLinearSwizzle(
+ int Width,
+ int Height,
+ int Depth,
+ int GobBlockHeight,
+ int GobBlockDepth,
+ int Bpp)
{
- BhMask = (BlockHeight * 8) - 1;
+ TexWidth = Width;
+ TexHeight = Height;
+ TexDepth = Depth;
+ TexGobBlockHeight = GobBlockHeight;
+ TexGobBlockDepth = GobBlockDepth;
+ TexBpp = Bpp;
+
+ BppShift = BitUtils.CountTrailingZeros32(Bpp);
+
+ SetMipLevel(0);
+ }
+
+ public void SetMipLevel(int Level)
+ {
+ BaseOffset = GetMipOffset(Level);
+
+ int Width = Math.Max(1, TexWidth >> Level);
+ int Height = Math.Max(1, TexHeight >> Level);
+ int Depth = Math.Max(1, TexDepth >> Level);
- BhShift = CountLsbZeros(BlockHeight * 8);
- BppShift = CountLsbZeros(Bpp);
+ GobBlockSizes GbSizes = AdjustGobBlockSizes(Height, Depth);
- int WidthInGobs = (int)MathF.Ceiling(Width * Bpp / 64f);
+ BhMask = GbSizes.Height - 1;
+ BdMask = GbSizes.Depth - 1;
- GobStride = 512 * BlockHeight * WidthInGobs;
+ BhShift = BitUtils.CountTrailingZeros32(GbSizes.Height);
+ BdShift = BitUtils.CountTrailingZeros32(GbSizes.Depth);
- XShift = CountLsbZeros(512 * BlockHeight);
+ XShift = BitUtils.CountTrailingZeros32(GobSize * GbSizes.Height * GbSizes.Depth);
+
+ RobAndSliceSizes GsSizes = GetRobAndSliceSizes(Width, Height, GbSizes);
+
+ RobSize = GsSizes.RobSize;
+ SliceSize = GsSizes.SliceSize;
+ }
+
+ public int GetImageSize(int MipsCount)
+ {
+ int Size = GetMipOffset(MipsCount);
+
+ Size = (Size + 0x1fff) & ~0x1fff;
+
+ return Size;
}
- private int CountLsbZeros(int Value)
+ public int GetMipOffset(int Level)
{
- int Count = 0;
+ int TotalSize = 0;
- while (((Value >> Count) & 1) == 0)
+ for (int Index = 0; Index < Level; Index++)
{
- Count++;
+ int Width = Math.Max(1, TexWidth >> Index);
+ int Height = Math.Max(1, TexHeight >> Index);
+ int Depth = Math.Max(1, TexDepth >> Index);
+
+ GobBlockSizes GbSizes = AdjustGobBlockSizes(Height, Depth);
+
+ RobAndSliceSizes RsSizes = GetRobAndSliceSizes(Width, Height, GbSizes);
+
+ TotalSize += BitUtils.DivRoundUp(Depth, GbSizes.Depth) * RsSizes.SliceSize;
}
- return Count;
+ return TotalSize;
}
- public int GetSwizzleOffset(int X, int Y)
+ private struct GobBlockSizes
+ {
+ public int Height;
+ public int Depth;
+
+ public GobBlockSizes(int GobBlockHeight, int GobBlockDepth)
+ {
+ this.Height = GobBlockHeight;
+ this.Depth = GobBlockDepth;
+ }
+ }
+
+ private GobBlockSizes AdjustGobBlockSizes(int Height, int Depth)
+ {
+ int GobBlockHeight = TexGobBlockHeight;
+ int GobBlockDepth = TexGobBlockDepth;
+
+ int Pow2Height = BitUtils.Pow2RoundUp(Height);
+ int Pow2Depth = BitUtils.Pow2RoundUp(Depth);
+
+ while (GobBlockHeight * GobHeight > Pow2Height && GobBlockHeight > 1)
+ {
+ GobBlockHeight >>= 1;
+ }
+
+ while (GobBlockDepth > Pow2Depth && GobBlockDepth > 1)
+ {
+ GobBlockDepth >>= 1;
+ }
+
+ return new GobBlockSizes(GobBlockHeight, GobBlockDepth);
+ }
+
+ private struct RobAndSliceSizes
+ {
+ public int RobSize;
+ public int SliceSize;
+
+ public RobAndSliceSizes(int RobSize, int SliceSize)
+ {
+ this.RobSize = RobSize;
+ this.SliceSize = SliceSize;
+ }
+ }
+
+ private RobAndSliceSizes GetRobAndSliceSizes(int Width, int Height, GobBlockSizes GbSizes)
+ {
+ int WidthInGobs = BitUtils.DivRoundUp(Width * TexBpp, GobWidth);
+
+ int RobSize = GobSize * GbSizes.Height * GbSizes.Depth * WidthInGobs;
+
+ int SliceSize = BitUtils.DivRoundUp(Height, GbSizes.Height * GobHeight) * RobSize;
+
+ return new RobAndSliceSizes(RobSize, SliceSize);
+ }
+
+ public int GetSwizzleOffset(int X, int Y, int Z)
{
X <<= BppShift;
- int Position = (Y >> BhShift) * GobStride;
+ int YH = Y / GobHeight;
+
+ int Position = (Z >> BdShift) * SliceSize + (YH >> BhShift) * RobSize;
+
+ Position += (X / GobWidth) << XShift;
- Position += (X >> 6) << XShift;
+ Position += (YH & BhMask) * GobSize;
- Position += ((Y & BhMask) >> 3) << 9;
+ Position += ((Z & BdMask) * GobSize) << BhShift;
Position += ((X & 0x3f) >> 5) << 8;
Position += ((Y & 0x07) >> 1) << 6;
@@ -53,7 +180,7 @@ namespace Ryujinx.Graphics.Texture
Position += ((Y & 0x01) >> 0) << 4;
Position += ((X & 0x0f) >> 0) << 0;
- return Position;
+ return BaseOffset + Position;
}
}
} \ No newline at end of file