diff --git a/Ryujinx.Graphics/Gal/GalImage.cs b/Ryujinx.Graphics/Gal/GalImage.cs index f35cccaf77..991d47b496 100644 --- a/Ryujinx.Graphics/Gal/GalImage.cs +++ b/Ryujinx.Graphics/Gal/GalImage.cs @@ -10,6 +10,7 @@ namespace Ryujinx.Graphics.Gal public int TileWidth; public int GobBlockHeight; public int Pitch; + public int MaxMipmapLevel; public GalImageFormat Format; public GalMemoryLayout Layout; @@ -28,10 +29,11 @@ namespace Ryujinx.Graphics.Gal GalMemoryLayout Layout, GalImageFormat Format, TextureType TextureType, - GalTextureSource XSource = GalTextureSource.Red, - GalTextureSource YSource = GalTextureSource.Green, - GalTextureSource ZSource = GalTextureSource.Blue, - GalTextureSource WSource = GalTextureSource.Alpha) + int MaxMipmapLevel = 1, + GalTextureSource XSource = GalTextureSource.Red, + GalTextureSource YSource = GalTextureSource.Green, + GalTextureSource ZSource = GalTextureSource.Blue, + GalTextureSource WSource = GalTextureSource.Alpha) { this.Width = Width; this.Height = Height; @@ -40,6 +42,7 @@ namespace Ryujinx.Graphics.Gal this.GobBlockHeight = GobBlockHeight; this.Layout = Layout; this.Format = Format; + this.MaxMipmapLevel = MaxMipmapLevel; this.XSource = XSource; this.YSource = YSource; this.ZSource = ZSource; diff --git a/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs b/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs index 8db0b8a8c9..5714f3d891 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/ImageHandler.cs @@ -8,6 +8,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL public int Width => Image.Width; public int Height => Image.Height; + public int Depth => Image.Depth; public GalImageFormat Format => Image.Format; diff --git a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs index 802d02e690..eee3a4123e 100644 --- a/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs +++ b/Ryujinx.Graphics/Gal/OpenGL/OGLTexture.cs @@ -2,6 +2,7 @@ using OpenTK.Graphics.OpenGL; using Ryujinx.Common.Logging; using Ryujinx.Graphics.Texture; using System; +using System.Diagnostics; namespace Ryujinx.Graphics.Gal.OpenGL { @@ -46,6 +47,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL const int Level = 0; //TODO: Support mipmap textures. const int Border = 0; + Debug.Assert(Image.MaxMipmapLevel != 1, "No Mipmap support"); + TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Size); if (ImageUtils.IsCompressed(Image.Format)) @@ -87,7 +90,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL break; default: Logger.PrintWarning(LogClass.Gpu, $"Unsupported texture target type: {Target}"); - //throw new InvalidOperationException(); + throw new InvalidOperationException(); GL.TexImage2D( TextureTarget.Texture2D, Level, @@ -115,6 +118,8 @@ namespace Ryujinx.Graphics.Gal.OpenGL const int Level = 0; //TODO: Support mipmap textures. const int Border = 0; + Debug.Assert(Image.MaxMipmapLevel != 1, "No Mipmap support"); + TextureCache.AddOrUpdate(Key, new ImageHandler(Handle, Image), (uint)Data.Length); if (ImageUtils.IsCompressed(Image.Format) && !IsAstc(Image.Format)) @@ -195,14 +200,16 @@ namespace Ryujinx.Graphics.Gal.OpenGL { int TextureBlockWidth = ImageUtils.GetBlockWidth(Image.Format); int TextureBlockHeight = ImageUtils.GetBlockHeight(Image.Format); + int TextureBlockDepth = ImageUtils.GetBlockDepth(Image.Format); - // TODO: support 3D textures Data = ASTCDecoder.DecodeToRGBA8888( Data, TextureBlockWidth, - TextureBlockHeight, 1, + TextureBlockHeight, + TextureBlockDepth, Image.Width, - Image.Height, 1); + Image.Height, + Image.Depth); Image.Format = GalImageFormat.RGBA8 | (Image.Format & GalImageFormat.TypeMask); } @@ -211,16 +218,50 @@ namespace Ryujinx.Graphics.Gal.OpenGL PixelFormat Format, PixelType Type) = OGLEnumConverter.GetImageFormat(Image.Format); - GL.TexImage2D( - TextureTarget.Texture2D, - Level, - InternalFmt, - Image.Width, - Image.Height, - Border, - Format, - Type, - Data); + + switch (Target) + { + case TextureTarget.Texture2D: + GL.TexImage2D( + Target, + Level, + InternalFmt, + Image.Width, + Image.Height, + Border, + Format, + Type, + Data); + break; + case TextureTarget.Texture2DArray: + case TextureTarget.Texture3D: + GL.TexImage3D( + Target, + Level, + InternalFmt, + Image.Width, + Image.Height, + Image.Depth, + Border, + Format, + Type, + Data); + break; + default: + Logger.PrintWarning(LogClass.Gpu, $"Unsupported texture target type: {Target}"); + throw new InvalidOperationException(); + GL.TexImage2D( + TextureTarget.Texture2D, + Level, + InternalFmt, + Image.Width, + Image.Height, + Border, + Format, + Type, + Data); + break; + } } } @@ -283,6 +324,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL { int WrapS = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressU); int WrapT = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressV); + int WrapR = (int)OGLEnumConverter.GetTextureWrapMode(Sampler.AddressP); int MinFilter = (int)OGLEnumConverter.GetTextureMinFilter(Sampler.MinFilter, Sampler.MipFilter); int MagFilter = (int)OGLEnumConverter.GetTextureMagFilter(Sampler.MagFilter); @@ -291,6 +333,7 @@ namespace Ryujinx.Graphics.Gal.OpenGL GL.TexParameter(Target, TextureParameterName.TextureWrapS, WrapS); GL.TexParameter(Target, TextureParameterName.TextureWrapT, WrapT); + GL.TexParameter(Target, TextureParameterName.TextureWrapR, WrapR); GL.TexParameter(Target, TextureParameterName.TextureMinFilter, MinFilter); GL.TexParameter(Target, TextureParameterName.TextureMagFilter, MagFilter); diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs index c6332df57a..34ec16a274 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngine2d.cs @@ -38,6 +38,7 @@ namespace Ryujinx.Graphics.Graphics3d } } + // FIXME: SUPPORT NON 2D private void TextureCopy(NvGpuVmm Vmm) { CopyOperation Operation = (CopyOperation)ReadRegister(NvGpuEngine2dReg.CopyOperation); @@ -82,8 +83,6 @@ namespace Ryujinx.Graphics.Graphics3d long SrcKey = Vmm.GetPhysicalAddress(SrcAddress); long DstKey = Vmm.GetPhysicalAddress(DstAddress); - // TODO: all texture types - GalImage SrcTexture = new GalImage( SrcWidth, SrcHeight, 1, 1, diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs index d89059c0c5..195fce1acb 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngineM2mf.cs @@ -125,29 +125,29 @@ namespace Ryujinx.Graphics.Graphics3d if (SrcLinear) { - SrcSwizzle = new LinearSwizzle(SrcPitch, SrcCpp); + SrcSwizzle = new LinearSwizzle(SrcPitch, SrcCpp, SrcSizeX, SrcSizeY); } else { - SrcSwizzle = new BlockLinearSwizzle(SrcSizeX, SrcCpp, SrcBlockHeight); + SrcSwizzle = new BlockLinearSwizzle(SrcSizeX, SrcSizeY, SrcCpp, SrcBlockHeight); } ISwizzle DstSwizzle; if (DstLinear) { - DstSwizzle = new LinearSwizzle(DstPitch, DstCpp); + DstSwizzle = new LinearSwizzle(DstPitch, DstCpp, SrcSizeX, SrcSizeY); } else { - DstSwizzle = new BlockLinearSwizzle(DstSizeX, DstCpp, DstBlockHeight); + DstSwizzle = new BlockLinearSwizzle(DstSizeX, DstSizeY, DstCpp, DstBlockHeight); } for (int Y = 0; Y < YCount; Y++) for (int X = 0; X < XCount; X++) { - int SrcOffset = SrcSwizzle.GetSwizzleOffset(SrcPosX + X, SrcPosY + Y); - int DstOffset = DstSwizzle.GetSwizzleOffset(DstPosX + X, DstPosY + Y); + int SrcOffset = SrcSwizzle.GetSwizzleOffset(SrcPosX + X, SrcPosY + Y, 0); + int DstOffset = DstSwizzle.GetSwizzleOffset(DstPosX + X, DstPosY + Y, 0); long Src = SrcPA + (uint)SrcOffset; long Dst = DstPA + (uint)DstOffset; diff --git a/Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs b/Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs index 681552556c..9111365fd9 100644 --- a/Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs +++ b/Ryujinx.Graphics/Graphics3d/NvGpuEngineP2mf.cs @@ -119,14 +119,14 @@ namespace Ryujinx.Graphics.Graphics3d } else { - BlockLinearSwizzle Swizzle = new BlockLinearSwizzle(CopyWidth, 1, CopyGobBlockHeight); + BlockLinearSwizzle Swizzle = new BlockLinearSwizzle(CopyWidth, CopyHeight, 1, CopyGobBlockHeight); int SrcOffset = 0; for (int Y = CopyStartY; Y < CopyHeight && SrcOffset < CopySize; Y++) for (int X = CopyStartX; X < CopyWidth && SrcOffset < CopySize; X++) { - int DstOffset = Swizzle.GetSwizzleOffset(X, Y); + int DstOffset = Swizzle.GetSwizzleOffset(X, Y, 0); Vmm.WriteByte(CopyAddress + DstOffset, Buffer[SrcOffset++]); } diff --git a/Ryujinx.Graphics/Graphics3d/Texture/ASTCDecoder.cs b/Ryujinx.Graphics/Graphics3d/Texture/ASTCDecoder.cs index 1efa025523..39a3473cf3 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 9451291e9a..d8638839e3 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/BlockLinearSwizzle.cs @@ -11,7 +11,9 @@ namespace Ryujinx.Graphics.Texture private int XShift; private int GobStride; - public BlockLinearSwizzle(int Width, int Bpp, int BlockHeight = 16) + private int LayerZ; + + public BlockLinearSwizzle(int Width, int Height, int Bpp, int BlockHeight) { BhMask = (BlockHeight * 8) - 1; @@ -23,6 +25,8 @@ namespace Ryujinx.Graphics.Texture GobStride = 512 * BlockHeight * WidthInGobs; XShift = CountLsbZeros(512 * BlockHeight); + + LayerZ = Bpp * Width * Height; } private int CountLsbZeros(int Value) @@ -37,7 +41,7 @@ namespace Ryujinx.Graphics.Texture return Count; } - public int GetSwizzleOffset(int X, int Y) + public int GetSwizzleOffset(int X, int Y, int Z) { X <<= BppShift; @@ -53,7 +57,7 @@ namespace Ryujinx.Graphics.Texture Position += ((Y & 0x01) >> 0) << 4; Position += ((X & 0x0f) >> 0) << 0; - return Position; + return (Z * LayerZ) + Position; } } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs b/Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs index 583fc20c53..ddc4fe53ad 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/ISwizzle.cs @@ -2,6 +2,6 @@ namespace Ryujinx.Graphics.Texture { interface ISwizzle { - int GetSwizzleOffset(int X, int Y); + int GetSwizzleOffset(int X, int Y, int Z); } } \ No newline at end of file diff --git a/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs b/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs index 74f0fdad2c..e2b4fe2ae6 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/ImageUtils.cs @@ -4,6 +4,7 @@ using Ryujinx.Graphics.Memory; using System; using System.Collections.Generic; using OpenTK.Graphics.OpenGL; +using System.Diagnostics; namespace Ryujinx.Graphics.Texture { @@ -24,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; } } @@ -93,52 +96,53 @@ namespace Ryujinx.Graphics.Texture private static readonly Dictionary s_ImageTable = new Dictionary() { - { 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) }, + // TODO: check if everything is alright here + { 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, 4, TargetBuffer.Color) }, + { GalImageFormat.BptcUfloat, new ImageDescriptor(16, 4, 4, 4, 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, 4, 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, 4, TargetBuffer.Color) }, + { GalImageFormat.BC2, new ImageDescriptor(16, 4, 4, 4, TargetBuffer.Color) }, + { GalImageFormat.BC3, new ImageDescriptor(16, 4, 4, 4, TargetBuffer.Color) }, + { GalImageFormat.BC4, new ImageDescriptor(8, 4, 4, 4, TargetBuffer.Color) }, + { GalImageFormat.BC5, new ImageDescriptor(16, 4, 4, 4, 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, 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.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( @@ -225,6 +229,7 @@ namespace Ryujinx.Graphics.Texture throw new NotImplementedException(Format.ToString()); } + // TODO: non 2d public static byte[] ReadTexture(IMemory Memory, GalImage Image, long Position) { MemoryManager CpuMemory; @@ -238,52 +243,61 @@ namespace Ryujinx.Graphics.Texture CpuMemory = (MemoryManager)Memory; } + Debug.Assert(Image.TextureType == TextureType.TwoD, "non 2d texture read"); + ISwizzle Swizzle = TextureHelper.GetSwizzle(Image); 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++) + byte[] Data = new byte[Height * Pitch * Depth]; + for (int Z = 0; Z < Depth; Z++) { - int OutOffs = Y * Pitch; - - for (int X = 0; X < Width; X++) + for (int Y = 0; Y < Height; Y++) { - long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y); + int OutOffs = Y * Pitch + (Z * Width * Height * BytesPerPixel); - CpuMemory.ReadBytes(Position + Offset, Data, OutOffs, BytesPerPixel); + for (int X = 0; X < Width; X++) + { + long Offset = (uint)Swizzle.GetSwizzleOffset(X, Y, Z); - OutOffs += BytesPerPixel; + CpuMemory.ReadBytes(Position + Offset, Data, OutOffs, BytesPerPixel); + + OutOffs += BytesPerPixel; + } } } + return Data; } + // TODO: non 2d public static void WriteTexture(NvGpuVmm Vmm, GalImage Image, long Position, byte[] Data) { ISwizzle Swizzle = TextureHelper.GetSwizzle(Image); 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; + Debug.Assert(Image.TextureType == TextureType.TwoD, "non 2d texture write"); + + 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); @@ -291,6 +305,7 @@ namespace Ryujinx.Graphics.Texture } } + // TODO: SUPPORT NON 2D public static bool CopyTexture( NvGpuVmm Vmm, GalImage SrcImage, @@ -319,8 +334,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); @@ -330,15 +345,31 @@ namespace Ryujinx.Graphics.Texture return true; } + // FIXME: Check if that does the trick public static int GetSize(GalImage Image) { ImageDescriptor Desc = GetImageDescriptor(Image.Format); + int ComponentCount = GetCoordsCountTextureType(Image.TextureType); + + if (IsArray(Image.TextureType)) + ComponentCount--; + int Width = DivRoundUp(Image.Width, Desc.BlockWidth); int Height = DivRoundUp(Image.Height, Desc.BlockHeight); + int Depth = DivRoundUp(Image.Depth, Desc.BlockDepth); - // TODO: multi format - return Desc.BytesPerPixel * Width * Height; + switch (ComponentCount) + { + case 1: + return Desc.BytesPerPixel * Width; + case 2: + return Desc.BytesPerPixel * Width * Height; + case 3: + return Desc.BytesPerPixel * Width * Height * Depth; + default: + throw new InvalidOperationException(); + } } public static int GetPitch(GalImageFormat Format, int Width) @@ -362,6 +393,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); @@ -380,12 +416,14 @@ namespace Ryujinx.Graphics.Texture return (Image.Width + AlignMask) & ~AlignMask; } - public static (int Width, int Height) GetImageSizeInBlocks(GalImage Image) + // TODO: non 2d + 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) diff --git a/Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs b/Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs index ef468e27b5..ed4250148d 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/LinearSwizzle.cs @@ -5,15 +5,18 @@ namespace Ryujinx.Graphics.Texture private int Pitch; private int Bpp; - public LinearSwizzle(int Pitch, int Bpp) + private int ZLayer; + + public LinearSwizzle(int Pitch, int Bpp, int Width, int Height) { - this.Pitch = Pitch; - this.Bpp = Bpp; + this.Pitch = Pitch; + this.Bpp = Bpp; + this.ZLayer = Width * Height * Bpp; } - public int GetSwizzleOffset(int X, int Y) + public int GetSwizzleOffset(int X, int Y, int Z) { - return X * Bpp + Y * Pitch; + return Z * ZLayer + 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 f636b6e2d9..b7eaa76c1c 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/TextureFactory.cs @@ -2,6 +2,7 @@ using Ryujinx.Common.Logging; using Ryujinx.Graphics.Gal; using Ryujinx.Graphics.Memory; using System; +using System.Diagnostics; namespace Ryujinx.Graphics.Texture { @@ -22,6 +23,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 || @@ -44,6 +47,11 @@ namespace Ryujinx.Graphics.Texture int Height = (Tic[5] & 0xffff) + 1; int Depth = ((Tic[5] >> 16) & 0x3fff) + 1; + if (TextureType == TextureType.OneD) + { + Height = 1; + } + if (TextureType == TextureType.TwoD || TextureType == TextureType.OneD) { Depth = 1; @@ -58,6 +66,7 @@ namespace Ryujinx.Graphics.Texture Layout, Format, TextureType, + MaxMipmapLevel, XSource, YSource, ZSource, diff --git a/Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs b/Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs index 6ac91d8b59..4dbe82b476 100644 --- a/Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs +++ b/Ryujinx.Graphics/Graphics3d/Texture/TextureHelper.cs @@ -9,9 +9,11 @@ namespace Ryujinx.Graphics.Texture public static ISwizzle GetSwizzle(GalImage Image) { int BlockWidth = ImageUtils.GetBlockWidth (Image.Format); + int BlockHeight = ImageUtils.GetBlockHeight (Image.Format); int BytesPerPixel = ImageUtils.GetBytesPerPixel(Image.Format); int Width = (Image.Width + (BlockWidth - 1)) / BlockWidth; + int Height = (Image.Height + (BlockHeight - 1)) / BlockHeight; if (Image.Layout == GalMemoryLayout.BlockLinear) { @@ -19,11 +21,11 @@ namespace Ryujinx.Graphics.Texture Width = (Width + AlignMask) & ~AlignMask; - return new BlockLinearSwizzle(Width, BytesPerPixel, Image.GobBlockHeight); + return new BlockLinearSwizzle(Width, Height, BytesPerPixel, Image.GobBlockHeight); } else { - return new LinearSwizzle(Image.Pitch, BytesPerPixel); + return new LinearSwizzle(Image.Pitch, BytesPerPixel, Width, Height); } }