Add 3D textures and mipmap support on BlockLinearSwizzle

This commit is contained in:
gdkchan 2019-02-14 23:21:15 -02:00 committed by Thog
parent e4e08e6c67
commit 5ad8e13174
No known key found for this signature in database
GPG key ID: 0CD291558FAFDBC6
11 changed files with 226 additions and 42 deletions

View file

@ -34,6 +34,11 @@ namespace Ryujinx.Common
return value & -(long)size;
}
public static int DivRoundUp(int value, int dividend)
{
return (value + dividend - 1) / dividend;
}
public static ulong DivRoundUp(ulong value, uint dividend)
{
return (value + dividend - 1) / dividend;
@ -44,6 +49,24 @@ namespace Ryujinx.Common
return (value + dividend - 1) / dividend;
}
public static int Pow2RoundUp(int Value)
{
Value--;
Value |= (Value >> 1);
Value |= (Value >> 2);
Value |= (Value >> 4);
Value |= (Value >> 8);
Value |= (Value >> 16);
return ++Value;
}
public static int Pow2RoundDown(int Value)
{
return IsPowerOfTwo32(Value) ? Value : Pow2RoundUp(Value) >> 1;
}
public static bool IsPowerOfTwo32(int value)
{
return value != 0 && (value & (value - 1)) == 0;
@ -85,6 +108,18 @@ namespace Ryujinx.Common
return (ulong)count;
}
public static int CountTrailingZeros32(int Value)
{
int Count = 0;
while (((Value >> Count) & 1) == 0)
{
Count++;
}
return Count;
}
public static long ReverseBits64(long value)
{
return (long)ReverseBits64((ulong)value);

View file

@ -9,6 +9,7 @@ namespace Ryujinx.Graphics.Gal
public int Depth;
public int TileWidth;
public int GobBlockHeight;
public int GobBlockDepth;
public int Pitch;
public int MaxMipmapLevel;
@ -26,6 +27,7 @@ namespace Ryujinx.Graphics.Gal
int Depth,
int TileWidth,
int GobBlockHeight,
int GobBlockDepth,
GalMemoryLayout Layout,
GalImageFormat Format,
GalTextureTarget TextureTarget,
@ -40,6 +42,7 @@ namespace Ryujinx.Graphics.Gal
this.Depth = Depth;
this.TileWidth = TileWidth;
this.GobBlockHeight = GobBlockHeight;
this.GobBlockDepth = GobBlockDepth;
this.Layout = Layout;
this.Format = Format;
this.MaxMipmapLevel = MaxMipmapLevel;

View file

@ -119,7 +119,7 @@ namespace Ryujinx.Graphics.Graphics3d
SrcWidth,
SrcHeight,
SrcDepth, 1,
SrcBlockHeight,
SrcBlockHeight, 1,
SrcLayout,
SrcImgFormat,
SrcTarget);
@ -128,7 +128,7 @@ namespace Ryujinx.Graphics.Graphics3d
DstWidth,
DstHeight,
DstDepth, 1,
DstBlockHeight,
DstBlockHeight, 1,
DstLayout,
DstImgFormat,
DstTarget);

View file

@ -208,7 +208,7 @@ namespace Ryujinx.Graphics.Graphics3d
GalImageFormat Format = ImageUtils.ConvertSurface((GalSurfaceFormat)SurfFormat);
GalImage Image = new GalImage(Width, Height, 1, 1, GobBlockHeight, Layout, Format, GalTextureTarget.TwoD);
GalImage Image = new GalImage(Width, Height, 1, 1, GobBlockHeight, 1, Layout, Format, GalTextureTarget.TwoD);
Gpu.ResourceManager.SendColorBuffer(Vmm, Key, FbIndex, Image);
@ -263,7 +263,7 @@ namespace Ryujinx.Graphics.Graphics3d
GalImageFormat Format = ImageUtils.ConvertZeta((GalZetaFormat)ZetaFormat);
// TODO: Support non 2D?
GalImage Image = new GalImage(Width, Height, 1, 1, GobBlockHeight, Layout, Format, GalTextureTarget.TwoD);
GalImage Image = new GalImage(Width, Height, 1, 1, GobBlockHeight, 1, Layout, Format, GalTextureTarget.TwoD);
Gpu.ResourceManager.SendZetaBuffer(Vmm, Key, Image);
}

View file

@ -129,7 +129,11 @@ namespace Ryujinx.Graphics.Graphics3d
}
else
{
SrcSwizzle = new BlockLinearSwizzle(SrcSizeX, SrcSizeY, SrcCpp, SrcBlockHeight);
SrcSwizzle = new BlockLinearSwizzle(
SrcSizeX,
SrcSizeY, 1,
SrcBlockHeight, 1,
SrcCpp);
}
ISwizzle DstSwizzle;
@ -140,7 +144,11 @@ namespace Ryujinx.Graphics.Graphics3d
}
else
{
DstSwizzle = new BlockLinearSwizzle(DstSizeX, DstSizeY, DstCpp, DstBlockHeight);
DstSwizzle = new BlockLinearSwizzle(
DstSizeX,
DstSizeY, 1,
DstBlockHeight, 1,
DstCpp);
}
for (int Y = 0; Y < YCount; Y++)

View file

@ -119,7 +119,10 @@ namespace Ryujinx.Graphics.Graphics3d
}
else
{
BlockLinearSwizzle Swizzle = new BlockLinearSwizzle(CopyWidth, CopyHeight, 1, CopyGobBlockHeight);
BlockLinearSwizzle Swizzle = new BlockLinearSwizzle(
CopyWidth,
CopyHeight, 1,
CopyGobBlockHeight, 1, 1);
int SrcOffset = 0;

View file

@ -1,55 +1,178 @@
using Ryujinx.Common;
using System;
namespace Ryujinx.Graphics.Texture
{
class BlockLinearSwizzle : ISwizzle
{
private int BhShift;
private int BppShift;
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 XShift;
private int GobStride;
private int RobSize;
private int SliceSize;
public BlockLinearSwizzle(int Width, int Height, int Bpp, int BlockHeight)
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;
BhShift = CountLsbZeros(BlockHeight * 8);
BppShift = CountLsbZeros(Bpp);
BppShift = BitUtils.CountTrailingZeros32(Bpp);
int WidthInGobs = (int)MathF.Ceiling(Width * Bpp / 64f);
GobStride = 512 * BlockHeight * WidthInGobs;
XShift = CountLsbZeros(512 * BlockHeight);
SliceSize = Bpp * Width * Height;
SetMipLevel(0);
}
private int CountLsbZeros(int Value)
public void SetMipLevel(int Level)
{
int Count = 0;
BaseOffset = GetMipOffset(Level);
while (((Value >> Count) & 1) == 0)
int Width = Math.Max(1, TexWidth >> Level);
int Height = Math.Max(1, TexHeight >> Level);
int Depth = Math.Max(1, TexDepth >> Level);
GobBlockSizes GbSizes = AdjustGobBlockSizes(Height, Depth);
BhMask = GbSizes.Height - 1;
BdMask = GbSizes.Depth - 1;
BhShift = BitUtils.CountTrailingZeros32(GbSizes.Height);
BdShift = BitUtils.CountTrailingZeros32(GbSizes.Depth);
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;
}
public int GetMipOffset(int Level)
{
int TotalSize = 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;
}
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;
Position += (X >> 6) << XShift;
int Position = (Z >> BdShift) * SliceSize + (YH >> BhShift) * RobSize;
Position += ((Y & BhMask) >> 3) << 9;
Position += (X / GobWidth) << XShift;
Position += (YH & BhMask) * GobSize;
Position += ((Z & BdMask) * GobSize) << BhShift;
Position += ((X & 0x3f) >> 5) << 8;
Position += ((Y & 0x07) >> 1) << 6;
@ -57,7 +180,7 @@ namespace Ryujinx.Graphics.Texture
Position += ((Y & 0x01) >> 0) << 4;
Position += ((X & 0x0f) >> 0) << 0;
return Z * SliceSize + Position;
return BaseOffset + Position;
}
}
}

View file

@ -35,14 +35,16 @@ namespace Ryujinx.Graphics.Texture
Layout = GalMemoryLayout.Pitch;
}
int BlockHeightLog2 = (Tic[3] >> 3) & 7;
int TileWidthLog2 = (Tic[3] >> 10) & 7;
int GobBlockHeightLog2 = (Tic[3] >> 3) & 7;
int GobBlockDepthLog2 = (Tic[3] >> 6) & 7;
int TileWidthLog2 = (Tic[3] >> 10) & 7;
int BlockHeight = 1 << BlockHeightLog2;
int TileWidth = 1 << TileWidthLog2;
int GobBlockHeight = 1 << GobBlockHeightLog2;
int GobBlockDepth = 1 << GobBlockDepthLog2;
int TileWidth = 1 << TileWidthLog2;
int Width = (Tic[4] & 0xffff) + 1;
int Height = (Tic[5] & 0xffff) + 1;
int Width = ((Tic[4] >> 0) & 0xffff) + 1;
int Height = ((Tic[5] >> 0) & 0xffff) + 1;
int Depth = ((Tic[5] >> 16) & 0x3fff) + 1;
if (TextureTarget == GalTextureTarget.OneD)
@ -64,7 +66,8 @@ namespace Ryujinx.Graphics.Texture
Height,
Depth,
TileWidth,
BlockHeight,
GobBlockHeight,
GobBlockDepth,
Layout,
Format,
TextureTarget,

View file

@ -1,4 +1,5 @@
using ChocolArm64.Memory;
using Ryujinx.Common;
using Ryujinx.Graphics.Gal;
using Ryujinx.Graphics.Memory;
@ -10,10 +11,12 @@ namespace Ryujinx.Graphics.Texture
{
int BlockWidth = ImageUtils.GetBlockWidth (Image.Format);
int BlockHeight = ImageUtils.GetBlockHeight (Image.Format);
int BlockDepth = ImageUtils.GetBlockDepth (Image.Format);
int BytesPerPixel = ImageUtils.GetBytesPerPixel(Image.Format);
int Width = (Image.Width + (BlockWidth - 1)) / BlockWidth;
int Height = (Image.Height + (BlockHeight - 1)) / BlockHeight;
int Width = BitUtils.DivRoundUp(Image.Width, BlockWidth);
int Height = BitUtils.DivRoundUp(Image.Height, BlockHeight);
int Depth = BitUtils.DivRoundUp(Image.Depth, BlockDepth);
if (Image.Layout == GalMemoryLayout.BlockLinear)
{
@ -21,7 +24,13 @@ namespace Ryujinx.Graphics.Texture
Width = (Width + AlignMask) & ~AlignMask;
return new BlockLinearSwizzle(Width, Height, BytesPerPixel, Image.GobBlockHeight);
return new BlockLinearSwizzle(
Width,
Height,
Depth,
Image.GobBlockHeight,
Image.GobBlockDepth,
BytesPerPixel);
}
else
{

View file

@ -217,7 +217,7 @@ namespace Ryujinx.Graphics.VDec
GalImage Image = new GalImage(
OutputConfig.SurfaceWidth,
OutputConfig.SurfaceHeight, 1, 1,
OutputConfig.GobBlockHeight,
OutputConfig.GobBlockHeight, 1,
GalMemoryLayout.BlockLinear,
GalImageFormat.RGBA8 | GalImageFormat.Unorm,
GalTextureTarget.TwoD);

View file

@ -416,7 +416,7 @@ namespace Ryujinx.HLE.HOS.Services.Android
{
image = new GalImage(
fbWidth,
fbHeight, 1, 1, BlockHeight,
fbHeight, 1, 1, BlockHeight, 1,
GalMemoryLayout.BlockLinear,
imageFormat,
GalTextureTarget.TwoD);