aboutsummaryrefslogtreecommitdiff
path: root/Ryujinx.Graphics/Graphics3d/Texture
diff options
context:
space:
mode:
Diffstat (limited to 'Ryujinx.Graphics/Graphics3d/Texture')
-rw-r--r--Ryujinx.Graphics/Graphics3d/Texture/ASTCDecoder.cs1
-rw-r--r--Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs165
-rw-r--r--Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs8
-rw-r--r--Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs241
-rw-r--r--Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs36
-rw-r--r--Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs65
-rw-r--r--Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs17
7 files changed, 434 insertions, 99 deletions
diff --git a/Ryujinx.Graphics/Graphics3d/Texture/ASTCDecoder.cs b/Ryujinx.Graphics/Graphics3d/Texture/ASTCDecoder.cs
index 1efa0255..00158dc1 100644
--- a/Ryujinx.Graphics/Graphics3d/Texture/ASTCDecoder.cs
+++ b/Ryujinx.Graphics/Graphics3d/Texture/ASTCDecoder.cs
@@ -72,6 +72,7 @@ namespace Ryujinx.Graphics.Texture
if (BlockZ != 1 || Z != 1)
{
+ // TODO: Support 3D textures?
throw new ASTCDecoderException("3D compressed textures unsupported!");
}
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
diff --git a/Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs b/Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs
index 583fc20c..2e0e8aed 100644
--- a/Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs
+++ b/Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs
@@ -2,6 +2,12 @@ namespace Ryujinx.Graphics.Texture
{
interface ISwizzle
{
- int GetSwizzleOffset(int X, int Y);
+ int GetSwizzleOffset(int X, int Y, int Z);
+
+ void SetMipLevel(int Level);
+
+ int GetMipOffset(int Level);
+
+ int GetImageSize(int MipsCount);
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs b/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs
index f958e1de..c4208935 100644
--- a/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs
+++ b/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs
@@ -1,4 +1,6 @@
using ChocolArm64.Memory;
+using OpenTK.Graphics.OpenGL;
+using Ryujinx.Common;
using Ryujinx.Graphics.Gal;
using Ryujinx.Graphics.Memory;
using System;
@@ -23,14 +25,16 @@ namespace Ryujinx.Graphics.Texture
public int BytesPerPixel { get; private set; }
public int BlockWidth { get; private set; }
public int BlockHeight { get; private set; }
+ public int BlockDepth { get; private set; }
public TargetBuffer Target { get; private set; }
- public ImageDescriptor(int BytesPerPixel, int BlockWidth, int BlockHeight, TargetBuffer Target)
+ public ImageDescriptor(int BytesPerPixel, int BlockWidth, int BlockHeight, int BlockDepth, TargetBuffer Target)
{
this.BytesPerPixel = BytesPerPixel;
this.BlockWidth = BlockWidth;
this.BlockHeight = BlockHeight;
+ this.BlockDepth = BlockDepth;
this.Target = Target;
}
}
@@ -92,52 +96,52 @@ namespace Ryujinx.Graphics.Texture
private static readonly Dictionary<GalImageFormat, ImageDescriptor> s_ImageTable =
new Dictionary<GalImageFormat, ImageDescriptor>()
{
- { GalImageFormat.RGBA32, new ImageDescriptor(16, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.RGBA16, new ImageDescriptor(8, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.RG32, new ImageDescriptor(8, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.RGBX8, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.RGBA8, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.BGRA8, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.RGB10A2, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.R32, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.RGBA4, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.BptcSfloat, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
- { GalImageFormat.BptcUfloat, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
- { GalImageFormat.BGR5A1, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.RGB5A1, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.RGB565, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.BGR565, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.BptcUnorm, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
- { GalImageFormat.RG16, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.RG8, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.R16, new ImageDescriptor(2, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.R8, new ImageDescriptor(1, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.R11G11B10, new ImageDescriptor(4, 1, 1, TargetBuffer.Color) },
- { GalImageFormat.BC1, new ImageDescriptor(8, 4, 4, TargetBuffer.Color) },
- { GalImageFormat.BC2, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
- { GalImageFormat.BC3, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
- { GalImageFormat.BC4, new ImageDescriptor(8, 4, 4, TargetBuffer.Color) },
- { GalImageFormat.BC5, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
- { GalImageFormat.Astc2D4x4, new ImageDescriptor(16, 4, 4, TargetBuffer.Color) },
- { GalImageFormat.Astc2D5x5, new ImageDescriptor(16, 5, 5, TargetBuffer.Color) },
- { GalImageFormat.Astc2D6x6, new ImageDescriptor(16, 6, 6, TargetBuffer.Color) },
- { GalImageFormat.Astc2D8x8, new ImageDescriptor(16, 8, 8, TargetBuffer.Color) },
- { GalImageFormat.Astc2D10x10, new ImageDescriptor(16, 10, 10, TargetBuffer.Color) },
- { GalImageFormat.Astc2D12x12, new ImageDescriptor(16, 12, 12, TargetBuffer.Color) },
- { GalImageFormat.Astc2D5x4, new ImageDescriptor(16, 5, 4, TargetBuffer.Color) },
- { GalImageFormat.Astc2D6x5, new ImageDescriptor(16, 6, 5, TargetBuffer.Color) },
- { GalImageFormat.Astc2D8x6, new ImageDescriptor(16, 8, 6, TargetBuffer.Color) },
- { GalImageFormat.Astc2D10x8, new ImageDescriptor(16, 10, 8, TargetBuffer.Color) },
- { GalImageFormat.Astc2D12x10, new ImageDescriptor(16, 12, 10, TargetBuffer.Color) },
- { GalImageFormat.Astc2D8x5, new ImageDescriptor(16, 8, 5, TargetBuffer.Color) },
- { GalImageFormat.Astc2D10x5, new ImageDescriptor(16, 10, 5, TargetBuffer.Color) },
- { GalImageFormat.Astc2D10x6, new ImageDescriptor(16, 10, 6, TargetBuffer.Color) },
-
- { GalImageFormat.D16, new ImageDescriptor(2, 1, 1, TargetBuffer.Depth) },
- { GalImageFormat.D24, new ImageDescriptor(4, 1, 1, TargetBuffer.Depth) },
- { GalImageFormat.D24S8, new ImageDescriptor(4, 1, 1, TargetBuffer.DepthStencil) },
- { GalImageFormat.D32, new ImageDescriptor(4, 1, 1, TargetBuffer.Depth) },
- { GalImageFormat.D32S8, new ImageDescriptor(8, 1, 1, TargetBuffer.DepthStencil) }
+ { GalImageFormat.RGBA32, new ImageDescriptor(16, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.RGBA16, new ImageDescriptor(8, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.RG32, new ImageDescriptor(8, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.RGBX8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.RGBA8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.BGRA8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.RGB10A2, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.R32, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.RGBA4, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.BptcSfloat, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
+ { GalImageFormat.BptcUfloat, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
+ { GalImageFormat.BGR5A1, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.RGB5A1, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.RGB565, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.BGR565, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.BptcUnorm, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
+ { GalImageFormat.RG16, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.RG8, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.R16, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.R8, new ImageDescriptor(1, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.R11G11B10, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Color) },
+ { GalImageFormat.BC1, new ImageDescriptor(8, 4, 4, 1, TargetBuffer.Color) },
+ { GalImageFormat.BC2, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
+ { GalImageFormat.BC3, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
+ { GalImageFormat.BC4, new ImageDescriptor(8, 4, 4, 1, TargetBuffer.Color) },
+ { GalImageFormat.BC5, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D4x4, new ImageDescriptor(16, 4, 4, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D5x5, new ImageDescriptor(16, 5, 5, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D6x6, new ImageDescriptor(16, 6, 6, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D8x8, new ImageDescriptor(16, 8, 8, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D10x10, new ImageDescriptor(16, 10, 10, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D12x12, new ImageDescriptor(16, 12, 12, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D5x4, new ImageDescriptor(16, 5, 4, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D6x5, new ImageDescriptor(16, 6, 5, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D8x6, new ImageDescriptor(16, 8, 6, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D10x8, new ImageDescriptor(16, 10, 8, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D12x10, new ImageDescriptor(16, 12, 10, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D8x5, new ImageDescriptor(16, 8, 5, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D10x5, new ImageDescriptor(16, 10, 5, 1, TargetBuffer.Color) },
+ { GalImageFormat.Astc2D10x6, new ImageDescriptor(16, 10, 6, 1, TargetBuffer.Color) },
+
+ { GalImageFormat.D16, new ImageDescriptor(2, 1, 1, 1, TargetBuffer.Depth) },
+ { GalImageFormat.D24, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Depth) },
+ { GalImageFormat.D24S8, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.DepthStencil) },
+ { GalImageFormat.D32, new ImageDescriptor(4, 1, 1, 1, TargetBuffer.Depth) },
+ { GalImageFormat.D32S8, new ImageDescriptor(8, 1, 1, 1, TargetBuffer.DepthStencil) }
};
public static GalImageFormat ConvertTexture(
@@ -241,26 +245,37 @@ namespace Ryujinx.Graphics.Texture
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
- (int Width, int Height) = GetImageSizeInBlocks(Image);
+ (int Width, int Height, int Depth) = GetImageSizeInBlocks(Image);
int BytesPerPixel = Desc.BytesPerPixel;
//Note: Each row of the texture needs to be aligned to 4 bytes.
int Pitch = (Width * BytesPerPixel + 3) & ~3;
- byte[] Data = new byte[Height * Pitch];
- for (int Y = 0; Y < Height; Y++)
- {
- int OutOffs = Y * Pitch;
+ int DataLayerSize = Height * Pitch * Depth;
+ byte[] Data = new byte[DataLayerSize * Image.LayerCount];
+
+ int TargetMipLevel = Image.MaxMipmapLevel <= 1 ? 1 : Image.MaxMipmapLevel - 1;
+ int LayerOffset = ImageUtils.GetLayerOffset(Image, TargetMipLevel);
- for (int X = 0; X < Width; X++)
+ for (int Layer = 0; Layer < Image.LayerCount; Layer++)
+ {
+ for (int Z = 0; Z < Depth; Z++)
{
- long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
+ for (int Y = 0; Y < Height; Y++)
+ {
+ int OutOffs = (DataLayerSize * Layer) + Y * Pitch + (Z * Width * Height * BytesPerPixel);
+
+ for (int X = 0; X < Width; X++)
+ {
+ long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y, Z);
- CpuMemory.ReadBytes(Position + Offset, Data, OutOffs, BytesPerPixel);
+ CpuMemory.ReadBytes(Position + (LayerOffset * Layer) + Offset, Data, OutOffs, BytesPerPixel);
- OutOffs += BytesPerPixel;
+ OutOffs += BytesPerPixel;
+ }
+ }
}
}
@@ -273,16 +288,17 @@ namespace Ryujinx.Graphics.Texture
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
- (int Width, int Height) = ImageUtils.GetImageSizeInBlocks(Image);
+ (int Width, int Height, int Depth) = ImageUtils.GetImageSizeInBlocks(Image);
int BytesPerPixel = Desc.BytesPerPixel;
int InOffs = 0;
+ for (int Z = 0; Z < Depth; Z++)
for (int Y = 0; Y < Height; Y++)
for (int X = 0; X < Width; X++)
{
- long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y);
+ long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y, Z);
Vmm.Memory.WriteBytes(Position + Offset, Data, InOffs, BytesPerPixel);
@@ -290,6 +306,7 @@ namespace Ryujinx.Graphics.Texture
}
}
+ // TODO: Support non 2D
public static bool CopyTexture(
NvGpuVmm Vmm,
GalImage SrcImage,
@@ -318,8 +335,8 @@ namespace Ryujinx.Graphics.Texture
for (int Y = 0; Y < Height; Y++)
for (int X = 0; X < Width; X++)
{
- long SrcOffset = (uint)SrcSwizzle.GetSwizzleOffset(SrcX + X, SrcY + Y);
- long DstOffset = (uint)DstSwizzle.GetSwizzleOffset(DstX + X, DstY + Y);
+ long SrcOffset = (uint)SrcSwizzle.GetSwizzleOffset(SrcX + X, SrcY + Y, 0);
+ long DstOffset = (uint)DstSwizzle.GetSwizzleOffset(DstX + X, DstY + Y, 0);
byte[] Texel = Vmm.ReadBytes(SrcAddress + SrcOffset, BytesPerPixel);
@@ -333,10 +350,41 @@ namespace Ryujinx.Graphics.Texture
{
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
+ int ComponentCount = GetCoordsCountTextureTarget(Image.TextureTarget);
+
+ if (IsArray(Image.TextureTarget))
+ ComponentCount--;
+
int Width = DivRoundUp(Image.Width, Desc.BlockWidth);
int Height = DivRoundUp(Image.Height, Desc.BlockHeight);
+ int Depth = DivRoundUp(Image.Depth, Desc.BlockDepth);
+
+ switch (ComponentCount)
+ {
+ case 1:
+ return Desc.BytesPerPixel * Width * Image.LayerCount;
+ case 2:
+ return Desc.BytesPerPixel * Width * Height * Image.LayerCount;
+ case 3:
+ return Desc.BytesPerPixel * Width * Height * Depth * Image.LayerCount;
+ default:
+ throw new InvalidOperationException($"Invalid component count: {ComponentCount}");
+ }
+ }
+
+ public static int GetGpuSize(GalImage Image, bool forcePitch = false)
+ {
+ return TextureHelper.GetSwizzle(Image).GetImageSize(Image.MaxMipmapLevel) * Image.LayerCount;
+ }
+
+ public static int GetLayerOffset(GalImage Image, int MipLevel)
+ {
+ if (MipLevel <= 0)
+ {
+ MipLevel = 1;
+ }
- return Desc.BytesPerPixel * Width * Height;
+ return TextureHelper.GetSwizzle(Image).GetMipOffset(MipLevel);
}
public static int GetPitch(GalImageFormat Format, int Width)
@@ -360,6 +408,11 @@ namespace Ryujinx.Graphics.Texture
return GetImageDescriptor(Format).BlockHeight;
}
+ public static int GetBlockDepth(GalImageFormat Format)
+ {
+ return GetImageDescriptor(Format).BlockDepth;
+ }
+
public static int GetAlignedWidth(GalImage Image)
{
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
@@ -378,12 +431,13 @@ namespace Ryujinx.Graphics.Texture
return (Image.Width + AlignMask) & ~AlignMask;
}
- public static (int Width, int Height) GetImageSizeInBlocks(GalImage Image)
+ public static (int Width, int Height, int Depth) GetImageSizeInBlocks(GalImage Image)
{
ImageDescriptor Desc = GetImageDescriptor(Image.Format);
return (DivRoundUp(Image.Width, Desc.BlockWidth),
- DivRoundUp(Image.Height, Desc.BlockHeight));
+ DivRoundUp(Image.Height, Desc.BlockHeight),
+ DivRoundUp(Image.Depth, Desc.BlockDepth));
}
public static int GetBytesPerPixel(GalImageFormat Format)
@@ -443,5 +497,66 @@ namespace Ryujinx.Graphics.Texture
default: throw new NotImplementedException(((int)Type).ToString());
}
}
+
+ public static TextureTarget GetTextureTarget(GalTextureTarget GalTextureTarget)
+ {
+ switch (GalTextureTarget)
+ {
+ case GalTextureTarget.OneD:
+ return TextureTarget.Texture1D;
+ case GalTextureTarget.TwoD:
+ case GalTextureTarget.TwoDNoMipMap:
+ return TextureTarget.Texture2D;
+ case GalTextureTarget.ThreeD:
+ return TextureTarget.Texture3D;
+ case GalTextureTarget.OneDArray:
+ return TextureTarget.Texture1DArray;
+ case GalTextureTarget.OneDBuffer:
+ return TextureTarget.TextureBuffer;
+ case GalTextureTarget.TwoDArray:
+ return TextureTarget.Texture2DArray;
+ case GalTextureTarget.CubeMap:
+ return TextureTarget.TextureCubeMap;
+ case GalTextureTarget.CubeArray:
+ return TextureTarget.TextureCubeMapArray;
+ default:
+ throw new NotSupportedException($"Texture target {GalTextureTarget} currently not supported!");
+ }
+ }
+
+ public static bool IsArray(GalTextureTarget TextureTarget)
+ {
+ switch (TextureTarget)
+ {
+ case GalTextureTarget.OneDArray:
+ case GalTextureTarget.TwoDArray:
+ case GalTextureTarget.CubeArray:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ public static int GetCoordsCountTextureTarget(GalTextureTarget TextureTarget)
+ {
+ switch (TextureTarget)
+ {
+ case GalTextureTarget.OneD:
+ return 1;
+ case GalTextureTarget.OneDArray:
+ case GalTextureTarget.OneDBuffer:
+ case GalTextureTarget.TwoD:
+ case GalTextureTarget.TwoDNoMipMap:
+ return 2;
+ case GalTextureTarget.ThreeD:
+ case GalTextureTarget.TwoDArray:
+ case GalTextureTarget.CubeMap:
+ return 3;
+ case GalTextureTarget.CubeArray:
+ return 4;
+ default:
+ throw new NotImplementedException($"TextureTarget.{TextureTarget} not implemented yet.");
+ }
+ }
}
}
diff --git a/Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs b/Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs
index ef468e27..e6509baa 100644
--- a/Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs
+++ b/Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs
@@ -1,3 +1,5 @@
+using System;
+
namespace Ryujinx.Graphics.Texture
{
class LinearSwizzle : ISwizzle
@@ -5,15 +7,39 @@ namespace Ryujinx.Graphics.Texture
private int Pitch;
private int Bpp;
- public LinearSwizzle(int Pitch, int Bpp)
+ private int SliceSize;
+
+ public LinearSwizzle(int Pitch, int Bpp, int Width, int Height)
{
- this.Pitch = Pitch;
- this.Bpp = Bpp;
+ this.Pitch = Pitch;
+ this.Bpp = Bpp;
+ SliceSize = Width * Height * Bpp;
+ }
+
+ public void SetMipLevel(int Level)
+ {
+ throw new NotImplementedException();
+ }
+
+ public int GetMipOffset(int Level)
+ {
+ if (Level == 1)
+ return SliceSize;
+ throw new NotImplementedException();
+ }
+
+ public int GetImageSize(int MipsCount)
+ {
+ int Size = GetMipOffset(MipsCount);
+
+ Size = (Size + 0x1fff) & ~0x1fff;
+
+ return Size;
}
- public int GetSwizzleOffset(int X, int Y)
+ public int GetSwizzleOffset(int X, int Y, int Z)
{
- return X * Bpp + Y * Pitch;
+ return Z * SliceSize + X * Bpp + Y * Pitch;
}
}
} \ No newline at end of file
diff --git a/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs b/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs
index 1f2d625e..a2ce86f5 100644
--- a/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs
+++ b/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs
@@ -12,6 +12,8 @@ namespace Ryujinx.Graphics.Texture
GalImageFormat Format = GetImageFormat(Tic);
+ GalTextureTarget TextureTarget = (GalTextureTarget)((Tic[4] >> 23) & 0xF);
+
GalTextureSource XSource = (GalTextureSource)((Tic[0] >> 19) & 7);
GalTextureSource YSource = (GalTextureSource)((Tic[0] >> 22) & 7);
GalTextureSource ZSource = (GalTextureSource)((Tic[0] >> 25) & 7);
@@ -19,6 +21,8 @@ namespace Ryujinx.Graphics.Texture
TextureSwizzle Swizzle = (TextureSwizzle)((Tic[2] >> 21) & 7);
+ int MaxMipmapLevel = (Tic[3] >> 28) & 0xF + 1;
+
GalMemoryLayout Layout;
if (Swizzle == TextureSwizzle.BlockLinear ||
@@ -31,22 +35,61 @@ 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 GobBlockHeight = 1 << GobBlockHeightLog2;
+ int GobBlockDepth = 1 << GobBlockDepthLog2;
+ int TileWidth = 1 << TileWidthLog2;
+
+ int Width = ((Tic[4] >> 0) & 0xffff) + 1;
+ int Height = ((Tic[5] >> 0) & 0xffff) + 1;
+ int Depth = ((Tic[5] >> 16) & 0x3fff) + 1;
+
+ int LayoutCount = 1;
- int BlockHeight = 1 << BlockHeightLog2;
- int TileWidth = 1 << TileWidthLog2;
+ // TODO: check this
+ if (ImageUtils.IsArray(TextureTarget))
+ {
+ LayoutCount = Depth;
+ Depth = 1;
+ }
+
+ if (TextureTarget == GalTextureTarget.OneD)
+ {
+ Height = 1;
+ }
- int Width = (Tic[4] & 0xffff) + 1;
- int Height = (Tic[5] & 0xffff) + 1;
+ if (TextureTarget == GalTextureTarget.TwoD || TextureTarget == GalTextureTarget.OneD)
+ {
+ Depth = 1;
+ }
+ else if (TextureTarget == GalTextureTarget.CubeMap)
+ {
+ // FIXME: This is a bit hacky but I guess it's fine for now
+ LayoutCount = 6;
+ Depth = 1;
+ }
+ else if (TextureTarget == GalTextureTarget.CubeArray)
+ {
+ // FIXME: This is a really really hacky but I guess it's fine for now
+ LayoutCount *= 6;
+ Depth = 1;
+ }
GalImage Image = new GalImage(
Width,
Height,
+ Depth,
+ LayoutCount,
TileWidth,
- BlockHeight,
+ GobBlockHeight,
+ GobBlockDepth,
Layout,
Format,
+ TextureTarget,
+ MaxMipmapLevel,
XSource,
YSource,
ZSource,
@@ -68,6 +111,10 @@ namespace Ryujinx.Graphics.Texture
GalTextureWrap AddressV = (GalTextureWrap)((Tsc[0] >> 3) & 7);
GalTextureWrap AddressP = (GalTextureWrap)((Tsc[0] >> 6) & 7);
+ bool DepthCompare = ((Tsc[0] >> 9) & 1) == 1;
+
+ DepthCompareFunc DepthCompareFunc = (DepthCompareFunc)((Tsc[0] >> 10) & 7);
+
GalTextureFilter MagFilter = (GalTextureFilter) ((Tsc[1] >> 0) & 3);
GalTextureFilter MinFilter = (GalTextureFilter) ((Tsc[1] >> 4) & 3);
GalTextureMipFilter MipFilter = (GalTextureMipFilter)((Tsc[1] >> 6) & 3);
@@ -85,7 +132,9 @@ namespace Ryujinx.Graphics.Texture
MinFilter,
MagFilter,
MipFilter,
- BorderColor);
+ BorderColor,
+ DepthCompare,
+ DepthCompareFunc);
}
private static GalImageFormat GetImageFormat(int[] Tic)
diff --git a/Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs b/Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs
index 6ac91d8b..33ccb0aa 100644
--- a/Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs
+++ b/Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs
@@ -1,4 +1,5 @@
using ChocolArm64.Memory;
+using Ryujinx.Common;
using Ryujinx.Graphics.Gal;
using Ryujinx.Graphics.Memory;
@@ -9,9 +10,13 @@ namespace Ryujinx.Graphics.Texture
public static ISwizzle GetSwizzle(GalImage Image)
{
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 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)
{
@@ -19,11 +24,17 @@ namespace Ryujinx.Graphics.Texture
Width = (Width + AlignMask) & ~AlignMask;
- return new BlockLinearSwizzle(Width, BytesPerPixel, Image.GobBlockHeight);
+ return new BlockLinearSwizzle(
+ Width,
+ Height,
+ Depth,
+ Image.GobBlockHeight,
+ Image.GobBlockDepth,
+ BytesPerPixel);
}
else
{
- return new LinearSwizzle(Image.Pitch, BytesPerPixel);
+ return new LinearSwizzle(Image.Pitch, BytesPerPixel, Width, Height);
}
}