diff options
Diffstat (limited to 'Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs')
| -rw-r--r-- | Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs | 165 |
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 |
